如何拆分字符串而不在数组中插入空字符串
假设存在匹配,我在使用正则表达式从字符串中分割字符时遇到问题。
我想从字符串的第一部分中分离出“m”或“f”字符,假设下一个字符是一个或多个数字,后跟可选的空格字符,后面是我拥有的数组中的字符串。
我试过了:
2.4.0 :006 > MY_SEPARATOR_TOKENS = ["-", " to "] => ["-", " to "] 2.4.0 :008 > str = "M14-19" => "M14-19" 2.4.0 :011 > str.split(/^(m|f)\d+[[:space:]]*#{Regexp.union(MY_SEPARATOR_TOKENS)}/i) => ["", "M", "19"]
注意数组开头的无关“”元素,并注意到最后一个表达式只是“19”,而我想要字符串中的所有其他内容(“14-19”)。
如何调整我的正则表达式,以便只有表达式的部分才能在数组中结束?
如果得到匹配,则空元素将始终存在,因为捕获的部分出现在字符串的开头,并且字符串的开头和匹配之间的字符串被添加到结果数组中,无论是空的还是非空的空字符串。 在获得匹配后shift
/ drop
它,或者只使用.reject { |c| c.empty? }
删除所有空数组元素 .reject { |c| c.empty? }
(请参阅如何从数组中删除空白元素? )。
然后, 14-
被\d+[[:space:]]...
模式部分吃掉(消耗) – 将它放入一个(?=...)
预测中,它只会检查模式匹配,但是赢了消耗人物。
使用类似的东西
MY_SEPARATOR_TOKENS = ["-", " to "] s = "M14-19" puts s.split(/^(m|f)(?=\d+[[:space:]]*#{Regexp.union(MY_SEPARATOR_TOKENS)})/i).drop(1) #=> ["M", "14-19"]
请参阅Ruby演示
从Ruby中的正则表达式中提取字符时,我发现match
更优雅:
string = "M14-19" string.match(/\A(?[M|F])(?\d{2}(-| to )\d{2})/)[1, 2] => ["M", "14-19"] # also can extract the symbols from match extract_string = string.match(/\A(?[M|F])(?\d{2}(-| to )\d{2})/) [[extract_string[:m], extract_string[:digits]] => ["M", "14-19"] string = 'M14 to 14' extract_string = string.match(/\A(?[M|F])(?\d{2}(-| to )\d{2})/)[1, 2] => ["M", "14 to 14"]
TOKENS = ["-", " to "] r = / (?<=\A[mMfF]) # match the beginning of the string and then one # of the 4 characters in a positive lookbehind (?= # begin positive lookahead \d+ # match one or more digits [[:space:]]* # match zero or more spaces (?:#{TOKENS.join('|')}) # match one of the tokens ) # close the positive lookahead /x # free-spacing regex definition mode
(?:#{TOKENS.join('|')})
被(?:-| to )
取代。
这当然可以用通常的方式编写。
r = /(?<=\A[mMfF])(?=\d+[[:space:]]*(?:#{TOKENS.join('|')}))/
在r
上分割时,你会在两个字符之间进行分割(在正向后观和正向前瞻之间),因此不会消耗任何字符。
"M14-19".split r #=> ["M", "14-19"] "M14 to 19".split r #=> ["M", "14 to 19"] "M14 To 19".split r #=> ["M14 To 19"]
如果希望在最后一个例子中返回["M", "14 To 19"]
,则将[mMfF]
更改为[mf]
并将/x
更改为/xi
。
你的代码中有一个bug。 不要养成这样做的习惯:
#{Regexp.union(MY_SEPARATOR_TOKENS)}
你正在为自己设置一个非常难以调试的问题。
这是发生了什么:
regex = Regexp.union(%w(ab)) # => /a|b/ /#{regex}/ # => /(?-mix:a|b)/ /#{regex.source}/ # => /a|b/
/(?-mix:a|b)/
是一个嵌入的子模式,其中包含正则表达式标志m
, i
和x
,它们独立于周围模式的设置。
考虑这种情况:
'CAT'[/#{regex}/i] # => nil
我们期望正则表达式i
标志匹配,因为它忽略大小写,但子表达式仍然只允许小写,导致匹配失败。
使用bare (a|b)
或添加source
成功,因为内部表达式获取主表达式i
:
'CAT'[/(a|b)/i] # => "A" 'CAT'[/#{regex.source}/i] # => "A"
有关此内容的详细讨论,请参阅“ 如何在Ruby中的其他正则表达式中嵌入正则表达式 ”。