regex - 如何在 Ruby 字符串中替换正则表达式匹配之外的内容?
问题描述
给定如下示例输入:
s = "an example with 'one' word and 'two and three' words inside quotes"
我正在尝试迭代引号之外的部分以进行一些替换。例如转换and
为&
但仅在引号之外得到:
an example with 'one' word & 'two and three' words inside quotes
如果要更改引号内,我可以简单地执行以下操作:
s.gsub(/'.*?'/){ |q| q.gsub(/and/, '&') }
要得到:
an example with 'one' word and 'two & three' words inside quotes
我主要尝试了两件事来使这种策略适应报价之外的情况。
首先,我首先尝试否定内部的正则表达式gsub
(即/'.*?'/
)。我想如果有一个像/v
我可以简单地做的后缀修饰符s.gsub(/'.*?'/v){ ... }
,不幸的是我找不到这样的东西。有一个负面的前瞻(即(?!pat)
),但我不认为这是我需要的。
其次,我尝试这样split
使用gsub!
:
puts s.split(/'.*?'/){ |r| r.gsub!(/and/, '&') }
使用split
我可以迭代引号之外的部分:
s.split(/'.*?'/){ |r| puts r }
要得到:
an example with
word and
words inside quotes
但是,我不能用gsub
or改变块内的这些部分gsub!
。我想我需要一个 的变异版本split
,类似于gsub
的变异版本scan
,但似乎没有这样的东西。
有没有一种简单的方法可以使这些方法中的任何一种都起作用?
解决方案
您可以匹配并捕获您需要保留的内容,并且只匹配您需要替换的内容。
利用
s.gsub(/('[^']*')|and/) { $1 || '&' }
s.gsub(/('[^']*')|and/) { |m| m == $~[1] ? $~[1] : '&' }
如果您需要匹配and
整个单词,请使用\band\b
in 模式而不是and
.
这种方法非常方便,因为您可以添加想要跳过的任意数量的特定模式。例如,您还想避免and
在双引号之间匹配整个单词:
s.gsub(/('[^']*'|"[^"]*")|\band\b/) { $1 || '&' }
或者,您想确保它也在使用转义引号的引号之间跳过字符串:
s.gsub(/('[^'\\]*(?:\\.[^'\\]*)*'|"[^"\\]*(?:\\.[^"\\]*)*")|\band\b/m) { $1 || '&' }
或者,如果它出现在圆形、方形、尖括号和大括号之外:
s.gsub(/(<[^<>]*>|\{[^{}]*\}|\([^()]*\)|\[[^\]\[]*\])|\band\b/m) { $1 || '&' }
匹配和捕获单引号之间的子字符串,只匹配您需要更改的内容。如果第 1 组匹配,则将其放回$1
,否则,替换为&
。第二行的替换块只是检查最后一个匹配的 Group 1 值是否与当前匹配的值相同,如果是,则将其放回原处,否则,替换为&
。
查看Ruby 演示。
正则表达式详细信息
('[^']*')
- 捕获组 #1:'
,零个或多个字符'
,然后是一个'
字符|
- 或者and
-and
子串。
推荐阅读
- google-apps-script - 谷歌表格 - 根据 2 件事复制和粘贴数据,游戏编号和名称
- ruby - Ruby Hash.new 带块需要深入解释
- javascript - 尝试在 React.Js 中创建“返回主菜单”按钮
- apex - SOQL 帮助:如何在 apex SOQL 中获取正确的联系人 ID,我想将联系人 ID 分配到任务创建中的字段 whoid
- html - 我有一个带有按钮的网站,该按钮应该居中,但由于某种原因它不是
- javascript - 更新 ES6 箭头函数,使其在 IE 上工作?
- azure - 带有服务总线触发器的 Azure 函数应用程序和 Web 作业在处理时丢失了一些消息
- python - 使用正则表达式分隔列
- mysql - 使用 Docker 自动创建数据库
- r - 如何在ggplot2条形图中分类一致地排序分组条