2008-12-18 117 views
4

String.length只會告訴我字符串中有多少個字符。 (事實上​​,在Ruby 1.9之前,它只會告訴我有多少字節,這些字節的用處就更小了。)如何計算Ruby中的字符串寬度?

我真的很希望能夠找出字符串有多少'en'。例如:

'foo'.width 
# => 3 

'moo'.width 
# => 3.5   # m's, w's, etc. are wide 

'foi'.width 
# => 2.5   # i's, j's, etc. are narrow 

'foo bar'.width 
# => 6.25   # spaces are very narrow 

更妙的是,如果我能得到第一n連接字符串的:

'foo'[0, 2.en] 
# => "fo" 

'filial'[0, 3.en] 
# => "fili" 

'foo bar baz'[0, 4.5en] 
# => "foo b" 

,更好的仍然是,如果我能制定戰略的整個事情。有些人認爲空間應該是0.25英寸,有些認爲應該是0.33等。

+1

這也在很大程度上依賴於用於渲染的字符串,沒有字體? – JesperE 2008-12-18 19:21:00

+1

你想獨立的字體?我認爲這不可能 – Keltia 2008-12-18 19:21:22

+1

我同意其他評論者的意見,除非你知道這是不可能的字體。 – 2008-12-18 19:32:01

回答

11

您應該使用RMagick寶石呈現一個「畫」您要使用的字體對象(可以加載的.ttf文件,例如)

的代碼會是這個樣子:

the_text = "TheTextYouWantTheWidthOf" 
    label = Draw.new 
    label.font = "Vera" #you can also specify a file name... check the rmagick docs to be sure 
    label.text_antialias(true) 
    label.font_style=Magick::NormalStyle 
    label.font_weight=Magick::BoldWeight 
    label.gravity=Magick::CenterGravity 
    label.text(0,0,the_text) 
    metrics = label.get_type_metrics(the_text) 
    width = metrics.width 
    height = metrics.height 

您可以在我的按鈕製作工具中看到它的動作:http://risingcode.com/button/everybodywangchungtonite

4

您可以嘗試創建一個標準的「寬度比例表」來計算一個aproximation,基本上你需要存儲每個字符的寬度然後遍歷字符串加起來的寬度。

我發現這臺here

Left, Width, Advance values for ArialBD16 'c' through 'm' 
Letter Left Width Advance 
c  1  7  9 
d  1  8  10 
e  1  8  9 
f  0  6  5 
g  0  9  10 
h  1  8  10 
i  1  2  4 
j  -1  4  4 
k  1  8  9 
l  1  2  4 
m  1  12  14 

如果你不想太認真,我想通過看的WebKit,蛤蚧,和OO.org開始,但我估計算法字距和尺寸計算並不是微不足道的。

4

如果您安裝了ImageMagick,則可以從命令行訪問此信息。

$ convert xc: -font ./.fonts/HelveticaRoundedLTStd-Bd.otf -pointsize 24 -debug annotate -annotate 0 'MyTestString' null: 2>&1 
2010-11-02T19:17:48+00:00 0:00.010 0.010u 6.6.5 Annotate convert[22496]: annotate.c/RenderFreetype/1155/Annotate 
    Font ./.fonts/HelveticaRoundedLTStd-Bd.otf; font-encoding none; text-encoding none; pointsize 24 
2010-11-02T19:17:48+00:00 0:00.010 0.010u 6.6.5 Annotate convert[22496]: annotate.c/GetTypeMetrics/736/Annotate 
    Metrics: text: MyTestString; width: 157; height: 29; ascent: 18; descent: -7; max advance: 24; bounds: 0,-5 20,17; origin: 158,0; pixels per em: 24,24; underline position: -1.5625; underline thickness: 0.78125 
2010-11-02T19:17:48+00:00 0:00.010 0.010u 6.6.5 Annotate convert[22496]: annotate.c/RenderFreetype/1155/Annotate 
    Font ./.fonts/HelveticaRoundedLTStd-Bd.otf; font-encoding none; text-encoding none; pointsize 24 

在Ruby中做到這一點,使用反引號:

result = `convert xc: -font #{path_to_font} -pointsize #{size} -debug annotate -annotate 0 '#{string}' null: 2>&1` 
if result =~ /width: (\d+);/ 
    $1 
end 
1

這是一個很好的問題!

我試圖解決它使用紅寶石中的pango/cairo SVG輸出。我可能會使用pango來計算寬度,然後使用一個簡單的svg元素。

我使用下面的代碼:

require "cairo" 
require "pango" 

paper = Cairo::Paper::A4_LANDSCAPE 
TEXT = "Don't you love me anymore?" 
def pac(surface) 
     cr = Cairo::Context.new(surface) 
     cr.select_font_face("Calibri", 
           Cairo::FONT_SLANT_NORMAL, 
           Cairo::FONT_WEIGHT_NORMAL) 
    cr.set_font_size(12) 
    extents = cr.text_extents(TEXT) 
    puts extents 
end 

Cairo::ImageSurface.new(*paper.size("pt")) do |surface| 
    cr = pac(surface) 
end 
3

使用ttfunk寶石從字體文件中讀取的指標。然後您可以獲取em中的一串文本的寬度。 Here's my pull request to get this example added to the gem.

require 'rubygems' 
require 'ttfunk' 
require 'valuable' 
# Everything you never wanted to know about glyphs: 
# http://chanae.walon.org/pub/ttf/ttf_glyphs.htm 

# this code is a substantial reworking of: 
# https://github.com/prawnpdf/ttfunk/blob/master/examples/metrics.rb 

class Font 
    attr_reader :file 

    def initialize(path_to_file) 
    @file = TTFunk::File.open(path_to_file) 
    end 

    def width_of(string) 
    string.split('').map{|char| character_width(char)}.inject{|sum, x| sum + x} 
    end 

    def character_width(character) 
    width_in_units = (horizontal_metrics.for(glyph_id(character)).advance_width) 
    width_in_units.to_f/units_per_em 
    end 

    def units_per_em 
    @u_per_em ||= file.header.units_per_em 
    end 

    def horizontal_metrics 
    @hm = file.horizontal_metrics 
    end 

    def glyph_id(character) 
    character_code = character.unpack("U*").first 
    file.cmap.unicode.first[character_code] 
    end 
end 

這是在行動:

>> din = Font.new("#{File.dirname(__FILE__)}/../../fonts/DIN/DINPro-Light.ttf") 
>> din.width_of("Hypertension") 
=> 5.832 
# which is correct! Hypertension in that font takes up about 5.832 em! It's over by maybe ... 0.015.