首页 文章

Ruby中的字符串连接

提问于
浏览
317

我正在寻找一种更优雅的方式来连接Ruby中的字符串 .

我有以下几行:

source = "#{ROOT_DIR}/" << project << "/App.config"

这样做有更好的方法吗?

就此而言 <<+ 之间有什么区别?

11 回答

  • 5

    您可以通过以下几种方式实现:

    • 正如您使用 << 所示,但这不是通常的方法

    • 使用字符串插值

    source = "#{ROOT_DIR}/#{project}/App.config"
    
    • with +
    source = "#{ROOT_DIR}/" + project + "/App.config"
    

    第二种方法在内存/速度方面似乎比我看到的更有效(虽然没有测量) . 当ROOT_DIR为零时,所有三种方法都会抛出未初始化的常量错误 .

    处理路径名时,您可能希望使用 File.join 以避免弄乱路径名分隔符 .

    最后,这是一个品味问题 .

  • 6

    + 运算符是正常的连接选择,可能是连接字符串的最快方法 .

    +<< 之间的区别在于 << 更改了左侧的对象,而 + 则没有 .

    irb(main):001:0> s = 'a'
    => "a"
    irb(main):002:0> s + 'b'
    => "ab"
    irb(main):003:0> s
    => "a"
    irb(main):004:0> s << 'b'
    => "ab"
    irb(main):005:0> s
    => "ab"
    
  • 504

    如果您只是连接路径,则可以使用Ruby自己的File.join方法 .

    source = File.join(ROOT_DIR, project, 'App.config')
    
  • 9

    来自http://greyblake.com/blog/2012/09/02/ruby-perfomance-tricks/

    使用 << aka concat 远比 += 更有效,因为后者创建一个时态对象并用新对象覆盖第一个对象 .

    require 'benchmark'
    
    N = 1000
    BASIC_LENGTH = 10
    
    5.times do |factor|
      length = BASIC_LENGTH * (10 ** factor)
      puts "_" * 60 + "\nLENGTH: #{length}"
    
      Benchmark.bm(10, '+= VS <<') do |x|
        concat_report = x.report("+=")  do
          str1 = ""
          str2 = "s" * length
          N.times { str1 += str2 }
        end
    
        modify_report = x.report("<<")  do
          str1 = "s"
          str2 = "s" * length
          N.times { str1 << str2 }
        end
    
        [concat_report / modify_report]
      end
    end
    

    输出:

    ____________________________________________________________
    LENGTH: 10
                     user     system      total        real
    +=           0.000000   0.000000   0.000000 (  0.004671)
    <<           0.000000   0.000000   0.000000 (  0.000176)
    += VS <<          NaN        NaN        NaN ( 26.508796)
    ____________________________________________________________
    LENGTH: 100
                     user     system      total        real
    +=           0.020000   0.000000   0.020000 (  0.022995)
    <<           0.000000   0.000000   0.000000 (  0.000226)
    += VS <<          Inf        NaN        NaN (101.845829)
    ____________________________________________________________
    LENGTH: 1000
                     user     system      total        real
    +=           0.270000   0.120000   0.390000 (  0.390888)
    <<           0.000000   0.000000   0.000000 (  0.001730)
    += VS <<          Inf        Inf        NaN (225.920077)
    ____________________________________________________________
    LENGTH: 10000
                     user     system      total        real
    +=           3.660000   1.570000   5.230000 (  5.233861)
    <<           0.000000   0.010000   0.010000 (  0.015099)
    += VS <<          Inf 157.000000        NaN (346.629692)
    ____________________________________________________________
    LENGTH: 100000
                     user     system      total        real
    +=          31.270000  16.990000  48.260000 ( 48.328511)
    <<           0.050000   0.050000   0.100000 (  0.105993)
    += VS <<   625.400000 339.800000        NaN (455.961373)
    
  • 76

    由于这是一条路径,我可能会使用数组和连接:

    source = [ROOT_DIR, project, 'App.config'] * '/'
    
  • 19

    这是另一个受this gist启发的基准测试 . 它比较动态和预定义字符串的连接( + ),追加( << )和插值( #{} ) .

    require 'benchmark'
    
    # we will need the CAPTION and FORMAT constants:
    include Benchmark
    
    count = 100_000
    
    
    puts "Dynamic strings"
    
    Benchmark.benchmark(CAPTION, 7, FORMAT) do |bm|
      bm.report("concat") { count.times { 11.to_s +  '/' +  12.to_s } }
      bm.report("append") { count.times { 11.to_s << '/' << 12.to_s } }
      bm.report("interp") { count.times { "#{11}/#{12}" } }
    end
    
    
    puts "\nPredefined strings"
    
    s11 = "11"
    s12 = "12"
    Benchmark.benchmark(CAPTION, 7, FORMAT) do |bm|
      bm.report("concat") { count.times { s11 +  '/' +  s12 } }
      bm.report("append") { count.times { s11 << '/' << s12 } }
      bm.report("interp") { count.times { "#{s11}/#{s12}"   } }
    end
    

    输出:

    Dynamic strings
                  user     system      total        real
    concat    0.050000   0.000000   0.050000 (  0.047770)
    append    0.040000   0.000000   0.040000 (  0.042724)
    interp    0.050000   0.000000   0.050000 (  0.051736)
    
    Predefined strings
                  user     system      total        real
    concat    0.030000   0.000000   0.030000 (  0.024888)
    append    0.020000   0.000000   0.020000 (  0.023373)
    interp    3.160000   0.160000   3.320000 (  3.311253)
    

    结论:MRI中的插值很重 .

  • 5

    我更喜欢使用路径名:

    require 'pathname' # pathname is in stdlib
    Pathname(ROOT_DIR) + project + 'App.config'
    

    关于来自ruby docs的 <<+

    + :返回包含与str连接的other_str的 new 字符串

    << :将给定对象连接到str . 如果对象是0到255之间的Fixnum,则在连接之前将其转换为字符 .

    这样的区别是什么变成第一个操作数( << 使得在发生的变化, + 返回新的字符串,它是内存较重),将是什么,如果第一个操作数是Fixnum对象( << 将增加,如果它是字符的代码等于该数字, + 会引发错误)

  • 85

    让我向你展示我的所有经验 .

    我有一个返回32k记录的查询,对于每个记录,我调用一种方法将该数据库记录格式化为格式化字符串,然后将其连接成一个字符串,在所有这个过程结束时将转换为磁盘中的文件 .

    我的问题是,据记录,大约24k,连接字符串的过程导致痛苦 .

    我是用常规''运算符做的 .

    当我改为'<<'时就像魔术一样 . 真的很快 .

    所以,我记得我的旧时代 - 有点像1998年 - 当我使用Java并使用''连接String并从String更改为StringBuffer时(现在我们Java开发人员拥有StringBuilder) .

    我相信Ruby世界中的/ <<进程与Java世界中的/ StringBuilder.append相同 .

    第一个在内存中重新分配整个对象,另一个只是指向一个新地址 .

  • 6

    连说你说?那么 #concat 方法怎么样?

    a = 'foo'
    a.object_id #=> some number
    a.concat 'bar' #=> foobar
    a.object_id #=> same as before -- string a remains the same object
    

    平心而论, concat 被别名为 << .

  • 2

    以下是更多方法:

    "String1" + "String2"
    
    "#{String1} #{String2}"
    
    String1<<String2
    

    等等 ...

  • 7

    您可以使用 +<< 运算符,但在ruby .concat 函数中是最优选的函数,因为它比其他运算符快得多 . 你可以像使用它一样 .

    source = "#{ROOT_DIR}/".concat(project.concat.("/App.config"))
    

相关问题