Ruby 如何编写消除数字和冒号之间空格的正则表达式?
我想将一个或两个数字之间的空格和冒号替换为空格、数字或行尾。如果我有一根像Ruby 如何编写消除数字和冒号之间空格的正则表达式?,ruby,regex,space,Ruby,Regex,Space,我想将一个或两个数字之间的空格和冒号替换为空格、数字或行尾。如果我有一根像 line = " 0 : 28 : 37.02" 结果应该是: " 0: 28: 37.02" 我尝试了以下方法: line.gsub!(/(\A|[ \u00A0|\r|\n|\v|\f])(\d?\d)[ \u00A0|\r|\n|\v|\f]:(\d|[ \u00A0|\r|\n|\v|\f]|\z)/, '\2:\3') # => " 0: 28 : 37.02" 它似乎与第一个:“”匹配,
line = " 0 : 28 : 37.02"
结果应该是:
" 0: 28: 37.02"
我尝试了以下方法:
line.gsub!(/(\A|[ \u00A0|\r|\n|\v|\f])(\d?\d)[ \u00A0|\r|\n|\v|\f]:(\d|[ \u00A0|\r|\n|\v|\f]|\z)/, '\2:\3')
# => " 0: 28 : 37.02"
它似乎与第一个
:“
”匹配,但第二个”:“
不匹配。我不明白为什么。这个问题
我将用注释(在自由间距模式下)定义您的正则表达式,以显示它在做什么
r =
/
( # begin capture group 1
\A # match beginning of string (or does it?)
| # or
[ \u00A0|\r|\n|\v|\f] # match one of the characters in the string " \u00A0|\r\n\v\f"
) # end capture group 1
(\d?\d) # match one or two digits in capture group 2
[ \u00A0|\r|\n|\v|\f] # match one of the characters in the string " \u00A0|\r\n\v\f"
: # match ":"
( # begin capture group 3
\d # match a digit
| # or
[ \u00A0|\r|\n|\v|\f] # match one of the characters in the string " \u00A0|\r\n\v\f"
| # or
\z # match the end of the string
) # end capture group 3
/x # free-spacing regex definition mode
请注意,“|”
不是字符类中的特殊字符(“或”)。它被视为一个普通的角色。(即使“|”
在字符类中被视为“或”,也没有任何作用,因为字符类用于强制匹配其中的任何一个字符。)
假设
line = " 0 : 28 : 37.02"
然后
在捕获组1中,行首(\A
)不匹配,因为它不是字符,并且只有字符不匹配(尽管我不知道为什么这不会引发异常)。“or”(“|”
)的特殊字符会导致正则表达式引擎尝试匹配字符串“\u00A0| \r\n\v\f”
中的一个字符。因此,它将匹配字符串行
开头三个空格中的一个
下一个捕获组2捕获“0”
。为此,捕获组1必须捕获了行
的索引2处的空间。然后再匹配一个空格和一个冒号,最后,捕获组3获取冒号后面的空格
子字符串'0:'
因此被替换为'\2:\3'#=>'0:'
,因此gsub
返回“0:28:37.02”
。请注意,'0'
之前的一个空格已被删除(但本应保留)
解决方案
下面介绍如何删除一个或多个Unicode空白字符中的最后一个,这些字符前面有一个或两个数字(而不是更多),后面是字符串末尾的冒号,或者后面是空格或数字的冒号。(呼!)
如本例所示,如果字符串中只有数字、空格和冒号,则不需要查找
您可以使用Ruby的
\p{}
构造\p{Space}
来代替POSIX表达式[[:Space:]
。两者都匹配一类Unicode空白字符,包括示例中所示的字符。问题出在哪里
" 0 : 28 : 37.02".gsub!(/(\d)(\s)(:)/,'\1\3')
=> " 0: 28: 37.02"
我将用注释(在自由间距模式下)定义您的正则表达式,以显示它在做什么
r =
/
( # begin capture group 1
\A # match beginning of string (or does it?)
| # or
[ \u00A0|\r|\n|\v|\f] # match one of the characters in the string " \u00A0|\r\n\v\f"
) # end capture group 1
(\d?\d) # match one or two digits in capture group 2
[ \u00A0|\r|\n|\v|\f] # match one of the characters in the string " \u00A0|\r\n\v\f"
: # match ":"
( # begin capture group 3
\d # match a digit
| # or
[ \u00A0|\r|\n|\v|\f] # match one of the characters in the string " \u00A0|\r\n\v\f"
| # or
\z # match the end of the string
) # end capture group 3
/x # free-spacing regex definition mode
请注意,“|”
不是字符类中的特殊字符(“或”)。它被视为一个普通的角色。(即使“|”
在字符类中被视为“或”,也没有任何作用,因为字符类用于强制匹配其中的任何一个字符。)
假设
line = " 0 : 28 : 37.02"
然后
在捕获组1中,行首(\A
)不匹配,因为它不是字符,并且只有字符不匹配(尽管我不知道为什么这不会引发异常)。“or”(“|”
)的特殊字符会导致正则表达式引擎尝试匹配字符串“\u00A0| \r\n\v\f”
中的一个字符。因此,它将匹配字符串行
开头三个空格中的一个
下一个捕获组2捕获“0”
。为此,捕获组1必须捕获了行
的索引2处的空间。然后再匹配一个空格和一个冒号,最后,捕获组3获取冒号后面的空格
子字符串'0:'
因此被替换为'\2:\3'#=>'0:'
,因此gsub
返回“0:28:37.02”
。请注意,'0'
之前的一个空格已被删除(但本应保留)
解决方案
下面介绍如何删除一个或多个Unicode空白字符中的最后一个,这些字符前面有一个或两个数字(而不是更多),后面是字符串末尾的冒号,或者后面是空格或数字的冒号。(呼!)
如本例所示,如果字符串中只有数字、空格和冒号,则不需要查找
您可以使用Ruby的
\p{}
构造\p{Space}
来代替POSIX表达式[[:Space:]
。两者都匹配一类Unicode空白字符,包括示例中所示的字符。排除第三个数字可以通过负回溯完成,但由于其他一个或两个数字的长度可变,因此不能对该部分使用正回溯
" 0 : 28 : 37.02".gsub!(/(\d)(\s)(:)/,'\1\3')
=> " 0: 28: 37.02"
line.gsub(/(?<!\d)(\d{1,2}) (?=:[ \d\$])/, '\1')
# => " 0: 28: 37.02"
line.gsub(/(?“0:28:37.02”
排除第三个数字可以通过负回溯完成,但由于其他一个或两个数字的长度可变,因此不能对该部分使用正回溯
line.gsub(/(?<!\d)(\d{1,2}) (?=:[ \d\$])/, '\1')
# => " 0: 28: 37.02"
line.gsub(/(?“0:28:37.02”
在建议的解决方案中,这是唯一一个我可以阅读并立即知道其作用的解决方案。只有当“:”后面有空格、数字或行尾时,你如何应用此答案?在建议的解决方案中,这是唯一一个我可以阅读并立即知道其作用的解决方案。只有当“:”时,你如何应用此答案后面是空格、数字或行尾?至少在测试时,使用gsub
而不是gsub!
。后者修改行
,因此如果您希望执行它,那么更改代码并再次运行它,而不记得重新初始化行
,您将得到一顿让您彻底崩溃的狗早餐我对发生的事情感到困惑。我不明白你为什么要使用bang版本。至少在测试时,使用gsub
而不是gsub!
。后者修改行,因此如果你想要执行它,那么就更改代码并运行它