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!
。后者修改
行,因此如果你想要执行它,那么就更改代码并运行它