我有一个有多个匹配项的正则表达式。我发现 $1 、 $2 等 .. 可以用来访问匹配的组。但是如何访问同一匹配组的多次出现?
请看下面的rubular页面。
http://rubular.com/r/nqHP1qAqRY
所以现在 1 美元给出 916,2 美元给出 NIL。如何访问 229885 ?有没有类似于 $1[1] 的东西?
我有一个有多个匹配项的正则表达式。我发现 $1 、 $2 等 .. 可以用来访问匹配的组。但是如何访问同一匹配组的多次出现?
请看下面的rubular页面。
http://rubular.com/r/nqHP1qAqRY
所以现在 1 美元给出 916,2 美元给出 NIL。如何访问 229885 ?有没有类似于 $1[1] 的东西?
首先,仅使用正则表达式解析基于 xml 的数据并不是一个好主意。而是使用一个库来解析 xml 文件,比如 nokogiri。
但是,如果您确定要使用此方法,则需要了解以下内容。正则表达式引擎在获得(令人愉悦的)匹配后立即停止。因此,您不能期望从一个正则表达式调用中获得字符串中的所有可能匹配项,您需要在每个已经发生的匹配之后应用新的正则表达式匹配来遍历字符串。你可以这样做:
# ruby 1.9.x version
regex = /<DATA size="(\d+)"/
str = your_string # Your string to be parsed
position = 0
matches = []
while(match = regex.match(str,position)) do # Until there are no matches anymore
position = match.end 0 # set position to the end of the last match
matches << match[1] # add the matched number to the matches-array
end
在此之后,您所有解析的数字都应该在matches
.
但是由于您的评论表明您使用的是ruby 1.8.x,所以我将在此处发布另一个版本,该版本适用于 1.8.x(这些版本中的方法定义不同)。
# ruby 1.8.x version
regex = /<DATA size="(\d+)"/
str = your_string # Your string to be parsed
matches = []
while(match = regex.match(str)) do # Until there are no matches anymore
str = match.post_match # set str to the part which is after the match.
matches << match[1] # add the matched number to the matches-array
end
要扩展我的评论并回答您的问题:
如果要将值存储在数组中,请修改块并收集而不是迭代:
> arr = xml.grep(/<DATA size="(\d+)"/).collect { |d| d.match /\d+/ }
> arr.each { |a| puts "==> #{a}" }
==> 916
==> 229885
这|d|
是普通的 Ruby 块参数语法;eachd
是匹配的字符串,从中提取数字。它不是最干净的 Ruby,尽管它很实用。
我仍然建议使用解析器;请注意,rexml 版本将是这样的(或多或少):
require 'rexml/document'
include REXML
doc = Document.new xml
arr = doc.elements.collect("//DATA") { |d| d.attributes["size"] }
arr.each { |a| puts "==> #{a}" }
将“XML”转换为实际 XML 后,您可以获得更多有用的数据:
doc = Document.new xml
arr = doc.elements.collect("//file") do |f|
name = f.elements["FILENAME"].attributes["path"]
size = f.elements["DATA"].attributes["size"]
[name, size]
end
arr.each { |a| puts "#{a[0]}\t#{a[1]}" }
~/Users/1.txt 916
~/Users/2.txt 229885
这在大多数正则表达式的实现中是不可能的。(AFAIK 只有 .NET 可以做到这一点。)
您将不得不使用替代解决方案,例如使用scan()
:等效于 Ruby 中 Python 的 findall() 方法?.