Ruby 中的字符串连接

发布于 2024-07-10 08:02:48 字数 221 浏览 11 评论 0原文

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

我有以下几行:

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

有更好的方法吗?

那么 <<+ 之间有什么区别?

I am looking for a more elegant way of concatenating strings in Ruby.

I have the following line:

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

Is there a nicer way of doing this?

And for that matter what is the difference between << and +?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

北凤男飞 2024-07-17 08:02:48

您可以通过多种方式做到这一点:

  1. << 所示,但这不是通常方式
  2. 使用字符串插值

    source = "#{ROOT_DIR}/#{project}/App.config" 
      
  3. 使用 +

    源=“#{ROOT_DIR}/”+项目+“/App.config” 
      

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

处理路径名时,您可能需要使用 File.join 来避免弄乱路径名分隔符。

归根结底,这是一个品味问题。

You can do that in several ways:

  1. As you shown with << but that is not the usual way
  2. With string interpolation

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

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

The second method seems to be more efficient in term of memory/speed from what I've seen (not measured though). All three methods will throw an uninitialized constant error when ROOT_DIR is nil.

When dealing with pathnames, you may want to use File.join to avoid messing up with pathname separator.

In the end, it is a matter of taste.

女皇必胜 2024-07-17 08:02:48

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

+<< 之间的区别在于 << 更改其左侧的对象,而 + 没有。

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"

The + operator is the normal concatenation choice, and is probably the fastest way to concatenate strings.

The difference between + and << is that << changes the object on its left hand side, and + doesn't.

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"
柠檬色的秋千 2024-07-17 08:02:48

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

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

If you are just concatenating paths you can use Ruby's own File.join method.

source = File.join(ROOT_DIR, project, 'App.config')
已下线请稍等 2024-07-17 08:02:48

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

使用 << 又名 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)

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

Using << aka concat is far more efficient than +=, as the latter creates a temporal object and overrides the first object with the new object.

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

output:

____________________________________________________________
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)
吃不饱 2024-07-17 08:02:48

由于这是一条路径,我可能会使用数组并加入:

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

Since this is a path I'd probably use array and join:

source = [ROOT_DIR, project, 'App.config'] * '/'
汐鸠 2024-07-17 08:02:48

这是另一个受这个要点启发的基准测试。 它比较动态字符串和预定义字符串的串联 (+)、追加 (<<) 和插值 (#{})。

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 中的插值很重。

Here's another benchmark inspired by this gist. It compares concatenation (+), appending (<<) and interpolation (#{}) for dynamic and predefined strings.

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

output:

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)

Conclusion: interpolation in MRI is heavy.

哎呦我呸! 2024-07-17 08:02:48

我更喜欢使用路径名:

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

关于 ruby​​ 文档中的 <<+

+:返回一个 new 包含 other_str 连接到 str 的字符串

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

所以区别在于第一个操作数会变成什么(<< 进行适当的更改,+ 返回新字符串,因此内存更重)以及第一个操作数会是什么is Fixnum(<< 将添加,就好像它是代码等于该数字的字符,+ 将引发错误)

I'd prefer using Pathname:

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

about << and + from ruby docs:

+: Returns a new String containing other_str concatenated to str

<<: Concatenates the given object to str. If the object is a Fixnum between 0 and 255, it is converted to a character before concatenation.

so difference is in what becomes to first operand (<< makes changes in place, + returns new string so it is memory heavier) and what will be if first operand is Fixnum (<< will add as if it was character with code equal to that number, + will raise error)

半夏半凉 2024-07-17 08:02:48

让我向您展示我的所有经验。

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

我的问题是,根据记录,在 24k 左右,连接字符串的过程变得很痛苦。

我使用常规的“+”运算符来做到这一点。

当我更改为“<<”时 就像魔法一样。 真的很快。

所以,我记得我以前的时光 - 大概是 1998 年 - 当时我使用 Java 并使用“+”连接字符串,并从 String 更改为 StringBuffer(现在我们,Java 开发人员拥有 StringBuilder)。

我相信 + / << 的过程 在Ruby世界中与Java世界中的+/StringBuilder.append相同。

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

Let me show to you all my experience with that.

I had an query that returned 32k of records, for each record I called a method to format that database record into a formated string and than concatenate that into a String that at the end of all this process wil turn into a file in disk.

My problem was that by the record goes, around 24k, the process of concatenating the String turned on a pain.

I was doing that using the regular '+' operator.

When I changed to the '<<' was like magic. Was really fast.

So, I remembered my old times - sort of 1998 - when I was using Java and concatenating String using '+' and changed from String to StringBuffer (and now we, Java developer have the StringBuilder).

I believe that the process of + / << in Ruby world is the same as + / StringBuilder.append in the Java world.

The first reallocate the entire object in memory and the other just point to a new address.

任谁 2024-07-17 08:02:48

你说串联? 那么 #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 的别名为 <<

Concatenation you say? How about #concat method then?

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

In all fairness, concat is aliased as <<.

离旧人 2024-07-17 08:02:48

这里有更多方法可以做到这一点:

"String1" + "String2"

"#{String1} #{String2}"

String1<<String2

等等......

Here are more ways to do this:

"String1" + "String2"

"#{String1} #{String2}"

String1<<String2

And so on ...

痕至 2024-07-17 08:02:48

您还可以使用 %,如下所示:

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

此方法也适用于 '(单)引号。

You can also use % as follows:

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

This approach works with ' (single) quotation mark as well.

半城柳色半声笛 2024-07-17 08:02:48

您可以直接在字符串定义中连接:

nombre_apellido = "#{customer['first_name']} #{customer['last_name']} #{order_id}"

You can concatenate in string definition directly:

nombre_apellido = "#{customer['first_name']} #{customer['last_name']} #{order_id}"
遥远的绿洲 2024-07-17 08:02:48

您可以使用 +<< 运算符,但在 ruby​​ 中 .concat 函数是最优选的,因为它比其他运营商。 你可以像这样使用它。

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

You may use + or << operator, but in ruby .concat function is the most preferable one, as it is much faster than other operators. You can use it like.

source = "#{ROOT_DIR}/".concat(project.concat("/App.config"))
提赋 2024-07-17 08:02:48

情况很重要,例如:

# this will not work
output = ''

Users.all.each do |user|
  output + "#{user.email}\n"
end
# the output will be ''
puts output

# this will do the job
output = ''

Users.all.each do |user|
  output << "#{user.email}\n"
end
# will get the desired output
puts output

在第一个示例中,与 + 运算符连接不会更新 output 对象,但是,在第二个示例中,<< ; 运算符将在每次迭代时更新output 对象。 因此,对于上述类型的情况, << 更好。

Situation matters, for example:

# this will not work
output = ''

Users.all.each do |user|
  output + "#{user.email}\n"
end
# the output will be ''
puts output

# this will do the job
output = ''

Users.all.each do |user|
  output << "#{user.email}\n"
end
# will get the desired output
puts output

In the first example, concatenating with + operator will not update the output object,however, in the second example, the << operator will update the output object with each iteration. So, for the above type of situation, << is better.

痴骨ら 2024-07-17 08:02:48

对于您的特定情况,您还可以在构造字符串的文件路径类型时使用 Array#join :

string = [ROOT_DIR, project, 'App.config'].join('/')]

这具有自动将不同类型转换为字符串的令人愉快的副作用:

['foo', :bar, 1].join('/')
=>"foo/bar/1"

For your particular case you could also use Array#join when constructing file path type of string:

string = [ROOT_DIR, project, 'App.config'].join('/')]

This has a pleasant side effect of automatically converting different types to string:

['foo', :bar, 1].join('/')
=>"foo/bar/1"
她说她爱他 2024-07-17 08:02:48

对于木偶:

$username = 'lala'
notify { "Hello ${username.capitalize}":
    withpath => false,
}

For Puppet:

$username = 'lala'
notify { "Hello ${username.capitalize}":
    withpath => false,
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文