【问题标题】:How does ruby differentiate between single and double quoted strings? Are C pointers involved?ruby 如何区分单引号和双引号字符串?是否涉及 C 指针?
【发布时间】:2016-11-28 18:36:11
【问题描述】:

有谁知道 ruby​​ 解释器如何知道字符串文字(单引号字符串)和双引号字符串之间的区别?

我正在玩弦乐,我想弄清楚是否可以将它们从一个更改为另一个。

通过将字符串中的转义序列替换为它们各自的 ascii 代码,我能够在某种程度上做到这一点。

\n = 10 -> \\ = 92, n = 110

我把这个双引号字符串

"a\e[0;36m X \n"

解释时会导致

 a X

X 以青色字体显示。我将转义序列更改为前面带有反斜杠的字母。这仅在传递的字符串是双字符串时才有效。我没有任何运气传递单引号字符串并将其更改为双引号,因此我可以允许插值。最后,我并没有真正改变字符串,只是它的内容,所以它的行为方式就是这样。

这让我对弄清楚 ruby​​ 如何知道一个字符串是单引号还是双引号产生了兴趣。我确信它有这样做的机制,因为当我在 IRB 玩时,我就这样做了。

a = "One\nTwo\t Half\n"
=> "One\nTwo\t Half\n"
b = 'Three \n Four \f Five'
=> "Three \\n Four \\f Five"
puts a + b
One
Two  Half
Three \n Four \f Five
=> nil
c = a + b
One
Two  Half
Three \n Four \f Five
=> nil

如你所见,ruby 足够聪明,可以记住字符串的某些部分是单引号,而其他部分是双引号。我很想知道 ruby​​ 是否保留了对原始字符串的引用/指针,并且当添加字符串时,它们只是简单地链接在一起,因为它看起来不像是在创建一个新字符串。

我注意到的另一个奇怪的事情是没有办法从方法/函数返回字符串文字。如果有人可以指出我。让我们把这个留给另一个问题。

更新:

我现在正在玩

ObjectSpace._id2ref(obj.object_id)

所以从上面的例子中我尝试了这个。

a.object_id
=> 70219586904340
puts ObjectSpace._id2ref 70219586904340
One
Two  Half
=> nil
b.object_id
=> 70219590675520
puts ObjectSpace._id2ref 70219590675520
Three \n Four \f Five
=> nil
c = a + b
puts ObjectSpace._id2ref c.object_id
One
Two  Half
Three \n Four \f Five
=> nil

我现在正在播放这些对象,但我还找不到。我想在里面看到并看到objA + objB或类似的东西。

【问题讨论】:

  • “ruby 足够聪明,可以记住”——ruby 什么都不记得,解析器负责转义单引号字符串中的任何内容。
  • 我很想知道 ruby​​ 是否保留了对原始字符串的引用/指针,并且当添加字符串时,它们只是简单地链接在一起,因为它看起来不像是在创建一个新字符串。 -- puts some_string.object_id 看看。
  • 您在本主题中的第二个问题的答案是显而易见的:不,不可能涉及 C 指针,因为存在非基于 C 的 Ruby 实现(Opal 用 ECMAScript 和Ruby、Ruby.NET 和 IronRuby 用 C♯ 编写,JRuby 和 XRuby 用 Ja​​va 编写,Cardinal 用 NQP 和 PASM 编写,……)。

标签: ruby string object


【解决方案1】:

在解释器方面没有区别。单引号和双引号字符串仅存在于解析器级别1。如果解析器遇到单引号,它会按字面意思解析字符:

str = 'foo\nbar' #=> "foo\\nbar"
str.chars        #=> ["f", "o", "o", "\\", "n", "b", "a", "r"]
str.codepoints   #=> [102, 111, 111,  92,  110, 98,  97,  114]

如果解析器遇到双引号,它会将几个转义序列转换为它们各自的字符(例如,序列\n 转换为代码点为 10 的 ASCII 字符,即换行符):

str = "foo\nbar" #=> "foo\nbar"
str.chars        #=> ["f", "o", "o", "\n", "b", "a", "r"]
str.codepoints   #=> [102, 111, 111,  10,  98,  97,  114]

你甚至可以混合使用单引号和双引号:

str = 'foo' "\n" 'bar'
#=> "foo\nbar"

解析器将其视为单个字符串文字"foo\nbar"

不管怎样,没有“单引号字符串实例”“双引号字符串实例”,只有字符串实例。

Ruby 为您提供了几种创建字符串的文字('...'"..."%q{...}<<HEREDOC?...)。生成的对象都是一样的。


1 在内部,NODE_STR 用于静态字符串,NODE_DSTR 用于插值字符串,但您无法从 Ruby 中访问该级别。一旦你有了一个字符串实例,它就只是一堆字符。

【讨论】:

  • 非常有趣,一如既往。 str = 'foo' "\n" 'bar'。哇。有这么多不同的可接受语法,我很惊讶 Ruby 中仍然存在语法错误。
  • 很高兴知道这一点。解析器确实区分了两者。
  • 但是解释器如何跟踪objC 的部分是单引号而部分是双引号。从上面的例子中,记住c = a + b。所以我们有一个 NODE_STR + NODE_DSTR。结果字符串是 NODE_STR 还是 NODE_DSTR?我怀疑每个返回和/或连接的字符串都是 NODE_DSTR。谁能证实这一点?
  • @luis.madrigal 不,两者都是NODE_STR,因为在"One\nTwo\t Half\n" 中没有进行插值。但同样,NODE_STRNODE_DSTR 是 Ruby(特定于实现)内部解析树中的中间结构。这些不是 Ruby 对象。
【解决方案2】:

我注意到的另一个奇怪的事情是没有办法返回 来自方法/函数的字符串文字。如果有谁能指出 我到这个。

def do_stuff
  "hello"
end

puts do_stuff.class
puts do_stuff
p do_stuff


--output:--
String
hello
"hello"

【讨论】:

  • 我很确定,提出此类问题的人确实知道如何从方法中返回字符串;)。 OP 的意思可能是您不能从方法中返回单引号字符串。
猜你喜欢
  • 2011-01-05
  • 2013-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-06
  • 2015-08-05
  • 2011-03-27
相关资源
最近更新 更多