如何在Ruby中计算String的宽度?

String.length只会告诉我String中有多少个字符。 (实际上,在Ruby 1.9之前,它只会告诉我有多少字节,这些字节的用处更少。)

我真的希望能够找出一个字符串的’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 

如果我能得到String的第一个n en,那就更好了:

 'foo'[0, 2.en] # => "fo" 'filial'[0, 3.en] # => "fili" 'foo bar baz'[0, 4.5en] # => "foo b" 

如果我可以策划整个事情,那就更好了。 有些人认为空间应该是0.25en,有些人认为应该是0.33等。

您应该使用RMagick gem使用您想要的字体渲染“Draw”对象(您可以加载.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

您可以尝试创建一个标准化的“宽度比例表”来计算aproximation,基本上您需要存储每个字符的宽度,然后遍历字符串加起来的宽度。

我在这里找到了这张桌子:

 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,gecko和OO.org,但我猜测字距和大小计算的算法并不简单。

如果安装了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 

使用ttfunk gem从字体文件中读取指标。 然后,您可以获得em中的一串文本的宽度。 这是我的拉动请求,将此示例添加到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. 

这是一个很好的问题!

我正在尝试使用ruby中的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