quzhongwei 2008-6-18 11:52
A.7 字符串--(附:Here Document处理技巧)
一系列字符可以用一对单引号或双引号括起来成为字符串。Ruby的字符串是String类的对象。单引号和双引号括起来的字符串并不完全相同,比如:
ok = "OK"
puts "Hello -> #{ok}" # 输出:Hello -> OK
puts 'Hello -> #{ok}' # 输出:Hello -> #{ok}
从上面的例子可以看出:单引号的字符串会进行较少的表达式替换,双引号的字符串会进行更多的表达式替换。
单引号和双引号的多行字符串表示也可以换为用%表示。我们来看看下面的多行字符串表示:
OK = "Ruby"
puts %/#{OK}
.hello/
puts %Q[#{OK}
.hello]
puts %q{#{OK}
.hello}
puts %(/#{OK}
.hello)
我们发现,%表示多行字符串时,单独一个%和%Q的作用是一样的——同双引号功能一样。%q的功能和单引号表示一样。另外在这种表示法中你可以在%、%Q、%q后面用{{[和]}}括号把多行字符串括起来。
在Ruby中字符串的处理非常重要,字符串类中也定义了很多的处理字符串的方法。同时Ruby也定义了一种多行字符串的表示方式,被称为Here Document。它的语法格式如下:
<<标识字符串
内容
标识字符串
这里标识字符串要紧接着<<书写,并且前后两个标识字符串在形式上要相同:
ok = "Ruby"
puts <<ok
hello, world!
----ya!ya. #{ok}
ok
除非,你用单引号和双引号把第一个标识字符串括起来,来执行特定的替换功能:
ok = "Ruby"
puts <<"ok"
hello, world!
----ya!ya. #{ok}
ok
puts <<'ok'
hello, world!
----ya!ya. #{ok}
ok
上面两段代码说明:标识符被双引号括起来和没有括起来在效果上是一样的。
一般情况下结尾的标识符必须顶格写,当然在<<后面加上- (减号)时,结尾的标识符可以缩进书写:
ok = "Ruby"
puts <<-ok
hello, world!
----ya!ya. #{ok}
ok
下面的代码也许会让你觉得奇怪:
ok = "Ruby"
puts <<-ok, <<-hello
hello, world!
----ya!ya. #{ok}
ok
#{ok}
hello
它输出:
hello, world!
----ya!ya. Ruby
Ruby
Ruby的作者是这样解释的:<<标识符和结尾的标识符并不是一个整体,而“<<标识符”代表的就是多行字符串的内容,这些内容从“<<标识符”的第二行开始,到结尾字符串为止。这就出现了一个很有意思的语法:
def hello(str1, str2)
puts str1
puts str2
end
hello("Ruby", <<-hello)
hello!
hello
同样,下面的代码段也饶有趣味:[code]puts <<hello.insert(1, " hello")
hello
hello[/code]如果你把第二行的哪个hello顶格写将会发生IndexError,为什么?这当作这一讲的第一道作业题。
更让你惊奇的是下面这个程序:[code]def ok(arg1, arg2, arg3)
puts arg1
puts arg2
puts "OK, " + arg3
end
ok(<<hello, "Ruby", "Lua") #要求写在一行上
hello, Ruby
hello[/code]只要下面这行:
ok(<<hello, "Ruby", "Lua")
不分开行写——即就在一行上面,Ruby解释器会正常工作!(为什么?本讲第二个作业题。)
这一点对于用Ruby来做文档处理有很大的帮助,特别地,用这个技巧再结合序列化的相关技巧,你可以做出相当精彩的文稿处理。。
[[i] 本帖最后由 quzhongwei 于 2008-6-19 02:29 编辑 [/i]]
5swords 2008-6-18 21:20
第1个问题应该是产生空串,第2题就当它是个下一行开始的串。
[quote]这一点对于用Ruby来做文档处理有很大的帮助,特别地,用这个技巧再结合序列化的相关技巧,你可以做出相当精彩的文稿处理。。[/quote]
这一段很吸引人,不过文稿处理是什么东西?请多多指教。
neohsiao 2008-6-18 22:10
太好了,我还在新手区发了Here document的问题呢,终于有解答了,运气好!:lol
neohsiao 2008-6-19 00:01
第一个问题,是因为<<标识符是hello,而句子hello.insert(1, " hello")将在here document建议以后
执行,所以,当句子是:[code]puts <<hello.insert(1, " hello")
hello#第一个hello
hello#第二个hello[/code]时,第一个hello作为了<<标识符的结束符,那么这个字符串为空,为空时在1位置插入一个元素就会引起
索引错误INDEXERROR,而如果第一个hello前面有空格的话则不当作<<标识符的结束符,而当作元素然后再把第二个hello当作<<标识符的结束符。等效于:[code]str = <<hello
hello#第一个hello,如果前面没有空格则str内容结束,内容为空。
hello#第二个hello。
#这里str结束
str.insert(1,"hello")
#如果字符串第一个为空格,在1位置插入的话,会把元素往后移动,而不会出现覆盖第一
#个的现象。
put str[/code][size=5]
第二题没有看懂……[/size]:L
[[i] 本帖最后由 neohsiao 于 2008-6-19 00:05 编辑 [/i]]
quzhongwei 2008-6-19 02:31
现在,请再看看原文。
liuxueming 2008-7-1 16:28
只要下面这行:
ok(<<hello, "Ruby", "Lua")
不分开行写——即就在一行上面,Ruby解释器会正常工作!
------------------------------------------------------------
这条语句执行报错!
can't find string "hello" anywhere before EOF
他的报错是正确的。
vintager 2008-7-7 17:16
可以把<<后面的hello看作是占位符,实际内容在下一行到hello之间。
weywong 2008-8-26 21:59
Here Document够绕人的。例子中的代码,仔细想想完全合乎逻辑;可要自己写实在写不出来。
punkpopb 2008-8-30 01:38
第一题的意思我没了,就也是第2行的hello如果顶格写的话就成了标识符hello的结束,所以这时候实际上Here Document对象是个空字串,所以对空字串使用insert方法自然会产生错误!
不过为什么我安装的ruby186-26(windows xp(pack 2)),在SciTE中运行这段代码(第2行hello顶格)却是可以通过的,并且结果是正确的!
不明白这是怎么一回事,但是如果去掉第3行的hello就出现老师所说的错误。