我正在使用Ruby将系统中的版本号分解为其相应的部分。有两种格式需要考虑:
type version (date)
type date
我有一个regualr表达式可以处理version
并不总是存在的事实。它是^([^\s]+)\s([^\s]+)?\s?\(?(.*?)\)?$\
。
然而,虽然这有效但当version
不在字符串中时,可选的捕获组不存在,这是有道理的。例如(Ruby的输出):
['type', 'version', 'date']
['type', 'date', '']
有没有办法让RegEx在不存在的情况下为可选捕获组返回null?输出将是:
['type', 'version', 'date']
['type', '', 'date']
答案 0 :(得分:1)
如果您正在寻找以下功能:
type version (date)
type date
结果:
['type', 'version', 'date']
['type', , 'date']
您可能希望使用非捕获组,例如(?:version)
以及(version)|
中的(?:(version)|)
,这将允许您捕获某些内容或捕获'nothing / null / nil'
试试这个正则表达式:
^([^\s]+)\s(?:([^\s]*)\s|)\(?(.*)\)?$
我建议使用http://regex101.com来了解不同符号的含义。
答案 1 :(得分:0)
您可以使用此regex
来匹配两种格式:
/^(\S+)\s+(?:(\S+)\s+\((\S+)\)|(\S+))$/
我使用\S
代替[^\s]
。它们具有same meaning(任何非空格字符),但\S
更短且更易于阅读。
/ # regex delimiter
^ # match the start of the string
(\S+) # capturing group that matches one or more non-space characters (type)
\s+ # one or more space characters
(?: # start of a non-capturing group
# +--- alternative #1: format "type version (date)"
(\S+) # | capturing group for version
\s+ # |
\( # | match a literal '('
(\S+) # | capturing group for date
\) # | match a literal ')'
# +-------------------
| # OR - either match alternative #1 or alternative #2
# +--- alternative #2: format "type date"
(\S+) # | capturing group for date
# +-------------------
) # end of the non-capturing group
$ # match the end of the string
/ # regex delimiter
匹配此regex
的字符串产生:
irb (main)> "Type Version (Date)".match(/^(\S+)\s+(?:(\S+)\s+\((\S+)\)|(\S+))$/)
=> #<MatchData "Type Version (Date)" 1:"Type" 2:"Version" 3:"Date" 4:nil>
irb(main)> "Type Date".match(/^(\S+)\s+(?:(\S+)\s+\((\S+)\)|(\S+))$/)
=> #<MatchData "Type Date" 1:"Type" 2:nil 3:nil 4:"Date">
生成的MatchData
对象中有4个项目,因为regex
中有4个捕获组。替代品中存在的组被加起来,来自非匹配替代品的组被设置为nil
。
下一步是name the capturing groups。通过这种方式,我们可以更轻松地识别它们,并识别(和崩溃)替代方案。
现在regex
是:
/^(?<type>\S+)\s+(?:(?<version>\S+)\s+\((?<date>\S+)\)|(?<date>\S+))$/
并产生:
irb(main)> "Type Version (Date)".match(/^(?<type>\S+)\s+(?:(?<version>\S+)\s+\((?<date>\S+)\)|(?<date>\S+))$/)
=> #<MatchData "Type Version (Date)" type:"Type" version:"Version" date:"Date" date:nil>
irb(main)> "Type Date".match(/^(?<type>\S+)\s+(?:(?<version>\S+)\s+\((?<date>\S+)\)|(?<date>\S+))$/)
=> #<MatchData "Type Date" type:"Type" version:nil date:nil date:"Date">
最后一步是使用方法MatchData#named_captures
根据匹配的替代方法,在Hash
中获取包含date
正确值的匹配项。
irb(main)> "Type Version (Date)".match(/^(?<type>\S+)\s+(?:(?<version>\S+)\s+\((?<date>\S+)\)|(?<date>\S+))$/).named_captures
=> {"type"=>"Type", "version"=>"Version", "date"=>"Date"}
irb(main)> "Type Date".match(/^(?<type>\S+)\s+(?:(?<version>\S+)\s+\((?<date>\S+)\)|(?<date>\S+))$/).named_captures
=> {"type"=>"Type", "version"=>nil, "date"=>"Date"}
如果您需要在格式#2上获取空字符串而不是nil
version
,则可以在{{{{}}之前添加名为version
的空捕获组。 1}}组:
date
答案 2 :(得分:0)
正则表达式自由区。
strs = [
'type version (date)',
'type date'
]
results = strs.map do |str|
type, *version, date = str.split
[type, version[0].to_s, date.tr('()', '')]
end
p results
--output:--
[["type", "version", "date"], ["type", "", "date"]]
如果您希望nil
而不是空白字符串,请删除to_s
。在nil
之后,您可以编写如下内容:
if arr[1]
#do one thing
else
#do another thing
因为ruby中的空字符串被认为是true
,所以如果数组在索引1处有一个空字符串,if-branch将始终执行。在ruby中唯一被认为是false的东西是nil
和{ {1}}。