Ruby 巨坑爹的 String#gsub 方法

Guest · 发布于 2013年07月19日 · 最后由 blackanger 回复于 2013年08月05日 · 7071 次阅读
96

Ruby中怎样做到String replace all substring? gsub?

# 注意我这里的' \" '不是为了转义双引号,而就是为了表达\和"两个字符
'site=|http://jex.im/|'.gsub '|','\"'     # ok ? 
# =>  "site=\\\"http://jex.im/\\\"" 

想当然地这样写不小心就踩中地雷了 看下面的代码结果:

# 注意我这里的' \& '不是为了转义&,而就是为了表达\和&两个字符
'site=|http://jex.im/|'.gsub '|','\"'  
# => "site=|quot;http://jex.im/|quot;" 

你竟然需要这么写才能得到正确结果: TOT

'site=|http://jex.im/|'.gsub('|') { '\"' }  
# => "site=\\"http://jex.im/\\""

坑爹啊!!!!!!!!!!!!!!!!!! 想想假如你的replacement string 是从外部获得的,你不知道里面有'\1,&'这样的back reference,结果会多么令人崩溃啊!!!! (注意上面的'\1,&'显示不正确,"&"前面的"\"被吃掉了,Ruby China的BUG么?)

括弧,其实我的另类解决方案是这样的:

s.split(substr).join(replacement)

http://jex.im

同样,gsub!和sub以及sub!方法都有这样的坑。只有[]方法不会这样

s["abc"]=replacement
共收到 15 条回复
De6df3

Ruby 单引号是不会转义的!

2.0.0-p195 :001 > "site=|http://jex.im/|".gsub("|",'"')
 => "site=\"http://jex.im/\""

2.0.0-p195 :007 > 'site=|http://jex.im/|'.gsub '|',"\""
 => "site=\"http://jex.im/\""

2.0.0-p195 :008 > 'site=|http://jex.im/|'.gsub '|',"\""
 => "site="http://jex.im/""
96

#1楼 @huacnlee 你没明白,我这是特地构造出'\"'这样的示例代码的,不然怎么会出现'\"' 这样的串?

De6df3

#2楼 @jamchange 额,确实无法搞出来

353
1.9.3p429 :045 > '\&'
 => "\\&"

1.9.3p429 :026 > 'asd'.gsub('d', '<\&>')
 => "as<d>"

1.9.3p429 :047 > 'asd'.gsub('d', "<\\&>")
 => "as<d>"


186

你不是要去转义 &,而是应该去转义 \ 啊。因为 literal 被 ruby 读取的时候会做一次转义,所以你需要用 4 斜杠。不过单引号比较特殊,因为只有单引号和斜杠会转义,如果有斜杠后面不是这两种符号,会当成正常的一个斜杠。所以如果后面跟着其它字符单引号里用 3 斜杠也行。不过为了清楚,最好也用 4 个。

> 'abc'.gsub(/.+/, '\\\\&')
=> "\\&"

用户输入的话,因为不需要使用 literal string,把所有斜杠 double 一下就好了。

> r = 'a\\\''
=> "a\\'"
> 'abc'.gsub(/.+/, r.gsub('\\', '\\\\\\\\'))
=> "a\\'"

注意,你需要把一个斜杠替换成两个,但是需要输入 8 个(其实 6 个也可以,gsub 处理到最后落单的斜杠就不转义了)。因为 ruby 读取转义一次,gsub 解析的时候又转义一次。

结论是: 确实很坑

2880

\& 是代入 $&, 相当于 \0 ...

除了 \1, \2, \k<group> , 会代入的就下面这几个了:

$` -- \` 匹配前
$& -- \0, \& 匹配中
$' -- \' 匹配后
7楼 已删除
96

#5楼 @doitian 我写的'&'不是为了转义&,我就是要表达\和&这两个字符。。。啊啊啊~~你们都没看明白我要表达的什么啊

96

乃们好多人都不仔细看,回复的文不对题

186

#8楼 @jamchange 我的意思是你需要替换成 \& 的话,应该去 escape \

'site=|http://jex.im/|.gsub' '|','\\"'

353

楼主是想吐槽replacement里面有special match chars是吗 不过API都已经明确说明了这些情况了 http://ruby-doc.org/core-1.9.3/String.html#method-i-gsub

96

#11楼 @cantin 开始以为back reference应该在使用Regexp时才会出现,gsub这样的接口设计显然不合理,几乎所有第一个参数为string时,调用方式都应该用content.gsub(str1) {replacement} 才安全。因为参数str1是一个已知值,再使用\&这样的reference就显多余。 String应该用一个安全的replaceAll方法,一个方法有太多的参数形式,用起来就得格外小心,太不快乐了

487

@jamchange 你为啥不这么写呢?

    str = 'site=|http://jex.im/|'.gsub(/\|/, "\"")   
=> "site=\"http://jex.im/\""

gsub方法本来就是把第一个参数当匹配模式来用的。

96

#13楼 @blackanger 又是一个不认真看题的。你们需要一双像编译器一样犀利的眼睛

487

#14楼 @jamchange 好吧。可能是我没看懂题。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册