ruby - 正则表达式匹配不在括号内的管道或带有嵌套块的大括号
问题描述
我正在尝试解析一些 wiki 标记。例如,以下内容:
{{Some infobox royalty|testing
| name = Louis
| title = Prince Napoléon
| elevation_imperial_note= <ref name="usgs">{{cite web|url={{Gnis3|1802764}}|title=USGS}}</ref>
| a = [[AA|aa]] | b = {{cite
|title=TITLE
|author=AUTHOR}}
}}
可以是开始的文本。我首先删除了开头{{
和结尾}}
,所以我可以假设它们已经消失了。
我想在字符串上用不在大括号或方括号内.split(<regex>)
的所有字符分割字符串。正则|
表达式需要忽略|
,[[AA|aa]]
和. 预期结果是:<ref name="usgs">{{cite web|url={{Gnis3|1802764}}|title=USGS}}</ref>
{{cite|title=TITLE|author=AUTHOR}}
[
'testing'
'name = Louis',
'title = Prince Napoléon',
'elevation_imperial_note= <ref name="usgs">{{cite web|url={{Gnis3|1802764}}|title=USGS}}</ref>',
'a = [[AA|aa]]',
'b = {{cite\n|title=TITLE\n|author=AUTHOR}}'
]
任何时候都可能有换行符,所以我不能只寻找\n|
. 如果里面有额外的空白,那很好。我可以轻松去除多余的\s*
或\n*
.
解决方案
以下是纯 Ruby 解决方案。我假设字符串中的大括号和括号是平衡的。
str =<<BITTER_END
Some infobox royalty|testing
| name = Louis
| title = Prince Napoléon
| elevation_imperial_note= <ref name="usgs">{{cite web|url={{Gnis3|1802764}}|title=USGS}}</ref>
| a = [[AA|aa]] | b = {{cite
|title=TITLE
|author=AUTHOR}}
BITTER_END
stack = []
last = 0
str.each_char.with_index.with_object([]) do |(c,i),locs|
puts "c=#{c}, i=#{i}, locs=#{locs}, stack=#{stack}"
case c
when ']', '}'
puts " pop #{c} from stack"
stack.pop
when '[', '{'
puts " push #{c} onto stack"
stack << c
when '|'
puts stack.empty? ? " record location of #{c}" : " skip | as stack is non-empty"
locs << i if stack.empty?
end
puts " after: locs=#{locs}, stack=#{stack}"
end.map do |i|
old_last = last
last = i+1
str[old_last..i-1].strip if i > 0
end.tap { |a| a << str[last..-1].strip if last < str.size }
#=> ["Some infobox royalty",
# "testing",
# "name = Louis",
# "title = Prince Napoléon",
# "elevation_imperial_note= <ref name=\"usgs\">
# {{cite web|url={{Gnis3|1802764}}|title=USGS}}</ref>",
# "a = [[AA|aa]]",
# "b = {{cite\n|title=TITLE\n|author=AUTHOR}}"]
请注意,为了提高可读性,我打破了作为返回数组1倒数第二个元素的字符串。
解释
有关如何确定要拆分的管道符号的位置的说明,请运行上面的 Heredoc 来确定str
(Heredoc 需要先取消缩进),然后运行以下代码。一切都会揭晓。(输出很长,所以要关注数组的变化locs
和stack
.)
stack = []
str.each_char.with_index.with_object([]) do |(c,i),locs|
puts "c=#{c}, i=#{i}, locs=#{locs}, stack=#{stack}"
case c
when ']', '}'
puts " pop #{c} from stack"
stack.pop
when '[', '{'
puts " push #{c} onto stack"
stack << c
when '|'
puts stack.empty? ? " record location of #{c}" : " skip | as stack is non-empty"
locs << i if stack.empty?
end
puts " after: locs=#{locs}, stack=#{stack}"
end
#=> [20, 29, 44, 71, 167, 183]
如果需要,可以按如下方式确认大括号和括号是否平衡。
def balanced?(str)
h = { '}'=>'{', ']'=>'[' }
stack = []
str.each_char do |c|
case c
when '[', '{'
stack << c
when ']', '}'
stack.last == h[c] ? (stack.pop) : (return false)
end
end
stack.empty?
end
balanced?(str)
#=> true
balanced?("[[{]}]")
#=> false
1 ...并且,为了透明起见,有机会使用某个词。
推荐阅读
- javascript - 可交互/可点击的 HTML 图像图
- java - 属性文件似乎正在产生空指针异常?
- cpu-architecture - 带有流水线的 cpu 中的 CPI
- bash - 使用 bash 完成从 /dev 获取文件
- mysql - 创建存储过程以从表中选择并将行插入日志表
- javascript - 以特定格式显示数组
- sql - SQL 请求将值放入列中
- asp.net-mvc - 使用我自己的登录页面使用 MVC 向 Azure AD 进行身份验证
- android - 隐藏 Android SDK sdkmanager cli 命令的进度条
- css - 为什么异步加载 CSS 文件不能解析 PageSpeed 的“延迟未使用的 CSS”条目?