Ruby 换行位置

Ruby 换行位置,ruby,string,Ruby,String,给定一个字符串,返回字符串中换行符开头的字符位置数组的最有效方法是什么 text =<<_ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi u

给定一个字符串,返回字符串中换行符开头的字符位置数组的最有效方法是什么

text =<<_
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in 
culpa qui officia deserunt mollit anim id est laborum.
_
我张贴我自己的答案。我愿意接受最快的方式作为公认的答案


当添加新答案时,此处的基准结果将更新

require "fruity"

compare do
  padde1 {find_newlines_padde1(text)}
  digitalross1 {find_newlines_digitalross1(text)}
  sawa1 {find_newlines1(text)}
  sawa2 {find_newlines2(text)}
end

# Running each test 512 times. Test will take about 1 second.
# digitalross1 is faster than sawa2 by 5x ± 0.1
# sawa2 is faster than sawa1 by 21.999999999999996% ± 1.0%
# sawa1 is faster than padde1 by 4.0000000000000036% ± 1.0%

与你的回答类似:

def find_newlines_padde1 text
  text.enum_for(:scan, /^/).map do
    $~.begin(0)
  end
end
您仍然可以通过以下方式获得一些性能:

需要“内联”
模块内核
内联:C do | builder|
builder.add_compile_标志'-std=c99'
建筑商c%q{
静态值find\u newlines\u padde2(值str){
字符换行符='\n';
char*s=RSTRING_PTR(str);
值res=rb_ary_new();
str=StringValue(str);
rb_ary_push(res,LONG2FIX(0));
用于(长位置=0;位置

如前所述,在1.9中使用
文本。每行。到a
。在1.8.7中调用
每行
也可以,但比只调用
到a要慢20%。

我本来打算在有更多答案的情况下这样做的。在不同的计算机上运行每个答案都有自己的基准是没有意义的。@SergioTulentsev你能给出一个答案吗这是一次尝试?我会的,但现在已经太晚了。也许明天吧。请注意,对于空字符串,sawa2返回
[]
,而sawa1、padde1和padde2返回
[0]
和DigitalRoss的方法会引发异常。请查看我的更新,除非我开始在内联c代码中编写内联汇编;-)因为
res[0]
将始终为0,也许它应该被删除或是可选的。我只是定制了此方法,以返回与@sawa方法相同的值。这完全取决于他希望如何使用此方法。但是,我不认为在此处添加零对性能至关重要,因为它位于循环之外,因此只会为执行时间添加一个常量。很抱歉,我无法正确运行
inline
。它似乎在
when
条件和其余条件之间使用冒号作为分隔符,这会返回语法错误。您使用的是哪个版本的ruby、RubyLine和哪个平台?这在ruby 1.9+上不起作用(
String
不再包括
可枚举的
),但
text.each_line.to_a…
都有。这是除padde使用C之外最快的一个。您的预期输出似乎不正确。第一个值始终为0,因此无法测量任何值。更糟糕的是,最后一个值393实际上不是最后一个换行符。它是sunt in之后的换行符,而不是est labourum之后的换行符位置。但是+1 anyway、 我喜欢比赛形式。这里也一样,感觉有点像代码高尔夫,但速度:)
def find_newlines_sawa1 s
  a = []
  s.scan(/^/){a.push($~.offset(0)[0])}
  a
end

find_newlines_sawa1(text) # => [0, 80, 155, 233, 313, 393]

def find_newlines_sawa2 s
  a = [0]
  s.split(/^/).each{|s| a.push(a.last + s.length)}
  a.pop
  a
end

find_newlines_sawa2(text) # => [0, 80, 155, 233, 313, 393]
def find_newlines_padde1 text
  text.enum_for(:scan, /^/).map do
    $~.begin(0)
  end
end
require "inline"
module Kernel
  inline :C do |builder|
    builder.add_compile_flags '-std=c99'
    builder.c %q{
      static VALUE find_newlines_padde2(VALUE str) {
        char newline = '\n';
        char* s = RSTRING_PTR(str);
        VALUE res = rb_ary_new();
        str = StringValue(str);
        rb_ary_push(res, LONG2FIX(0));
        for (long pos=0; pos<RSTRING_LEN(str)-1; pos++) {
          if (s[pos] == newline) {
             rb_ary_push(res, LONG2FIX(pos+1));
          }
        }
        return res;
      }
    }
  end
end
def find_newlines text
  s = 0
  [0] + text.to_a[0..-2].map { |e| s += e.size }
end