如何拆分字符串而不在数组中插入空字符串

假设存在匹配,我在使用正则表达式从字符串中分割字符时遇到问题。

我想从字符串的第一部分中分离出“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)/是一个嵌入的子模式,其中包含正则表达式标志mix ,它们独立于周围模式的设置。

考虑这种情况:

 'CAT'[/#{regex}/i] # => nil 

我们期望正则表达式i标志匹配,因为它忽略大小写,但子表达式仍然只允许小写,导致匹配失败。

使用bare (a|b)或添加source成功,因为内部表达式获取主表达式i

 'CAT'[/(a|b)/i] # => "A" 'CAT'[/#{regex.source}/i] # => "A" 

有关此内容的详细讨论,请参阅“ 如何在Ruby中的其他正则表达式中嵌入正则表达式 ”。