使用代码点连接不可变的ruby字符串

时间:2018-01-18 08:28:26

标签: ruby string encoding

在引入可选的冻结字符串的Ruby 2.3之前,可以使用铲运算符("<<",别名为" concat")附加字符串。但是,铲子操作符不仅仅是附加一个字符串,而是将数字视为代码点并perform various checks for the current and appending string encodings

$ x = "hello"
$ x << 33            # or: x << 0b111000 , x << 0x111, etc
#=> "hello!"

通过设置可选的#frozen_string_literal配置选项,字符串不再可变,因此无法使用铲子操作符,这会改变它所调用的对象。但是,通过重新分配变量来创建字符串似乎需要大量的编码工作是显式的,而不是隐式的

$ x = "hello"
$ x += 33
#=> TypeError: no implicit conversion of Integer into String

我经常通过执行以下操作来解决问题:

$ x = "hello"
$ x += [33].pack("U")
#=> hello!

如列出的under the directives for Array.pack,pack方法需要了解很多输入。到目前为止,我发现在用可变重新分配替换可变字符串连接(&#34; x&lt;&lt; y&#34;)&#34; x + = y&#34;时,这是一种痛苦。在现有的代码库中。

作为参考,我尝试更新someone's existing project to use immutable strings,但我并不总是清楚地知道字符串编码是什么。字节在8位,16位等之间变化很大,需要打包(&#39; n&#39;),打包(&#39; c&#39;),打包(&#39; U&#39; )等等。

虽然我认为最好的答案是在字符串编码中明确表示,以后可以避免潜在的错误,因为我可以访问这两个对象,但是不可变性本身应该要求现在需要更多的信息。

是否可以轻松替换铲运算符,它可以对现有和附加字符串提供相同类型的编码推断?理想情况下,与#34; x.concat(y)&#34;相同的C代码。但是没有进行到位更改,利用编码检查相同的编码检查而不违反不变性?

谢谢!

1 个答案:

答案 0 :(得分:0)

为了连接两个字符串,它们需要采用兼容的编码。 LosingPlace将尝试查找与两个操作数兼容的编码,并将第一个操作数转换为该编码。

String#<<

请注意,在最后一行中a = "a".encode('ascii-8bit') a.encoding #=> #<Encoding:ASCII-8BIT> b = "b" b.encoding #=> #<Encoding:UTF-8> a << b #=> "ab" a.encoding #=> #<Encoding:ASCII-8BIT> c = "ø" c.encoding #=> #<Encoding:UTF-8> a << c #=> "abø" a.encoding #=> #<Encoding:UTF-8> 的编码如何更改以适应a编码中不存在的字符。

如果右参数是数字,则此数字将被解释为当前编码中的代码点。如果该编码为ASCII-8BIT,则该数字可以从ASCII-8BIT转到0;如果编码为255,则最高可达UTF-81114111);其他编码有不同的范围。

要使用不可变字符串复制相同的功能,理想情况下,您可以这样做:

0x10FFFF

注意:最初我认为你有适当编码的原始字节,所以我建议x += y.encode(x.encoding) # instead of destructive `x << y` x += 33.chr(x.encoding) # instead of destructive `x << 33` 而不是String#force_encoding,但如果我理解你的意思,这实际上会给你错误的结果。