如何在许多匹配项中使用 ruby​​ gsub Regexp?

Posted

技术标签:

【中文标题】如何在许多匹配项中使用 ruby​​ gsub Regexp?【英文标题】:How to use ruby gsub Regexp with many matches? 【发布时间】:2012-02-24 07:21:19 【问题描述】:

我的 csv 文件内容在引用的文本中有双引号

test,first,line,"you are a "kind" man",thanks
again,second,li,"my "boss" is you",good

我需要用“”替换每个前面或后面没有逗号的双引号

test,first,line,"you are a ""kind"" man",thanks
again,second,li,"my ""boss"" is you",good

所以“”被“”代替了

我试过了

x.gsub(/([^,])"([^,])/, "#$1\"\"#$2")

但没用

【问题讨论】:

【参考方案1】:

您的正则表达式需要更粗一些,以防引号出现在第一个值的开头或最后一个值的结尾:

csv = <<ENDCSV
test,first,line,"you are a "kind" man",thanks
again,second,li,"my "boss" is you",good
more,""Someone" said that you're "cute"",yay
"watch out for this",and,also,"this test case"
ENDCSV

puts csv.gsub(/(?<!^|,)"(?!,|$)/,'""')
#=> test,first,line,"you are a ""kind"" man",thanks
#=> again,second,li,"my ""boss"" is you",good
#=> more,"""Someone"" said that you're ""cute""",yay
#=> "watch out for this",and,also,"this test case"

上述正则表达式使用 Ruby 1.9 中可用的否定后向和否定前瞻断言(锚)。

(?&lt;!^|,) — 在此位置之前不得有行首 (^) 或逗号 " — 查找双引号 (?!,|$) — 紧随此位置后不得有逗号或行尾 ($)

作为奖励,由于您实际上并未捕获任一侧的字符,因此您无需担心在替换字符串中正确使用 \1

有关详细信息,请参阅official Ruby regex documentation 中的“锚点”部分。


但是,对于您确实需要替换输出中的匹配项的情况,您可以使用以下任何一种:

"hello".gsub /([aeiou])/, '<\1>'            #=> "h<e>ll<o>"
"hello".gsub /([aeiou])/, "<\\1>"           #=> "h<e>ll<o>"
"hello".gsub(/([aeiou])/) |m| "<#$1>"   #=> "h<e>ll<o>"

您不能像以前那样在替换字符串中使用字符串插值:

"hello".gsub /([aeiou])/, "<#$1>"
 #=> "h<previousmatch>ll<previousmatch>"

...因为字符串插值发生了一次,之前gsub 已经运行。使用 gsub 的块形式为每个匹配重新调用块,此时全局 $1 已被适当地填充并可供使用。


编辑:对于 Ruby 1.8(你到底为什么要使用它?)你可以使用:

puts csv.gsub(/([^,\n\r])"([^,\n\r])/,'\1""\2')

【讨论】:

酷,我试图弄清楚如何在 Ruby 中进行负面的后向断言,但无法弄清楚。 感谢 Phrogz,它仅适用于 ruby​​ 1.9,您能建议 ruby​​ 1.8 的答案吗? @MahmoudKhaled 已更新为与 Ruby 1.8 一起使用。 (将来,如果您需要如此古老的 Ruby 版本,请在您的问题中包含此内容。Ruby 1.9.1 — 1.9 系列的第一个稳定版本 — 发布了三年 以前。) @Rivenfall 正确。这就是我所说的:“你不能在替换字符串中使用字符串插值”。您的意思是对原始问题发表评论吗?还是您误读了这个答案? 对不起,我误读了答案。我将添加 \0 是输入字符串(但不是 $0)【参考方案2】:

假设s 是一个字符串,这将起作用:

puts s.gsub(/([^,])"([^,])/, "\\1\"\"\\2")

【讨论】:

当您在内容中使用双引号时,最好使用单引号将它们括起来,如'\1""\2' 或使用第三种形式%q[\1""\2] 我有点担心我的答案实际上不足以满足您的情况,因为它无法处理很多事情,例如您的引号旁边是否真的有逗号数据。您可能需要做一些不基于正则表达式的更复杂的事情。

以上是关于如何在许多匹配项中使用 ruby​​ gsub Regexp?的主要内容,如果未能解决你的问题,请参考以下文章

Ruby 匹配第一次出现的字符串以进行 gsub 替换

带有索引/偏移量的Ruby gsub?

R语言sub函数和gsub函数替换(replace)匹配的字符串实战

Ruby gsub 替换值的单反斜杠?

如何使用 gsub 在 for 循环中找到完全匹配?

Ruby 正则表达式 \1 对 gsub 意味着啥