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

Ruby 如何拆分字符串而不在数组中插入空字符串,ruby,regex,split,Ruby,Regex,Split,假设存在匹配项,使用正则表达式从字符串中拆分字符时遇到问题 假设下一个字符是一个或多个数字,后跟可选的空格字符,后跟我拥有的数组中的一个字符串,我想从字符串的第一部分拆分出一个“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”字符

我试过:

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
/
删除它,也可以使用
删除所有空数组元素。拒绝{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中从正则表达式提取字符时,我发现
匹配
更加优雅:

string = "M14-19"
string.match(/\A(?<m>[M|F])(?<digits>\d{2}(-| to )\d{2})/)[1, 2]
=> ["M", "14-19"]
# also can extract the symbols from match
extract_string = string.match(/\A(?<m>[M|F])(?<digits>\d{2}(-| to )\d{2})/)
[[extract_string[:m], extract_string[:digits]]
=> ["M", "14-19"]
string = 'M14 to 14'
extract_string = string.match(/\A(?<m>[M|F])(?<digits>\d{2}(-| to )\d{2})/)[1, 2]
=> ["M", "14 to 14"]
string=“M14-19”
string.match(/\A(?[M | F])(?\d{2}(-to)\d{2})/)[1,2]
=>[“M”,“14-19”]
#还可以从匹配中提取符号
extract_string=string.match(/\A(?[M | F])(?\d{2}(-to)\d{2})/)
[[extract_string[:m],extract_string[:digits]]
=>[“M”,“14-19”]
字符串='M14到14'
extract_string=string.match(/\A(?[M|F])(?\d{2}(-to)\d{2})/)[1,2]
=>[“M”,“14至14”]

您的代码中正在酝酿一个bug。请不要养成这样做的习惯:

#{Regexp.union(MY_SEPARATOR_TOKENS)}
你给自己设置了一个很难调试的问题

下面是正在发生的事情:

regex = Regexp.union(%w(a b)) # => /a|b/
/#{regex}/ # => /(?-mix:a|b)/
/#{regex.source}/ # => /a|b/
/(?-mix:a | b)/
是一个嵌入式子模式,它有一组regex标志
m
i
x
,它们独立于周围模式的设置

考虑这种情况:

'CAT'[/#{regex}/i] # => nil
我们希望正则表达式
i
标志会匹配,因为它忽略大小写,但子表达式仍然只允许小写,导致匹配失败

使用裸
(a | b)
或添加
源代码
成功,因为内部表达式获取主表达式的
i

'CAT'[/(a|b)/i] # => "A"
'CAT'[/#{regex.source}/i] # => "A"
有关此问题的更多讨论,请参见“”

 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
当在
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到19”]
,请将
[mMfF]
更改为
[mf]
,将
/x
更改为
/xi

我不知道您所说的“拆分”或“字符串的第一部分”是什么意思。如果原始字符串是
str
您希望返回
str[1..-1]
str[0]=~/[mf]/i
和其他两个条件都满足时?如果不匹配,
str
将返回什么?你能用
drop 1
替换
reject
,这将更具描述性吗?@CarySwoveland:我修改了代码示例。
.drop(1)
只是去除第一个数组元素的另一种方法,但在大多数情况下,删除所有空元素是预期的行为。行
(?:#{TOKENS.join('.|')}
以前是
{Regexp.union(TOKENS)}
。我在阅读了@thetinman的答案后更改了它,这澄清了我对它的理解及其潜在缺陷。
"M14-19".split r
  #=> ["M", "14-19"]
"M14     to 19".split r
  #=> ["M", "14     to 19"]
"M14     To 19".split r
  #=> ["M14     To 19"]