1

使用 Ruby,我正在编写一个正则表达式,并且我需要能够删除括号之间出现的任何冒号。我知道我可以使用

"This is a (string :)".sub!(/\([^\)]*:/, '') 

这样做,但问题是这个函数也会随之删除上下文。有没有办法指定我只希望它删除冒号而不是整个匹配表达式?

4

4 回答 4

2

因此,一些正则表达式引擎支持所谓的前瞻和后瞻匹配,它们将匹配但不消耗字符。Ruby 确实支持前瞻,但不支持后瞻(以高性能方式更难做到),这意味着您可以很容易地坚持sub并删除右括号之前的冒号,但不能确保它在后左括号:

string = 'This is a (string :)'
string.sub /:(?=\))/, ''
# => 'This is a (string )'

另一种方法是使用子模式捕获(当您在正则表达式中使用分组时会自动发生)来重建没有不需要的部分的字符串,在这种情况下是冒号:

string.sub /(\([^:]+):\)/, '\1)'

\1是对第一组中匹配内容的反向引用,由未转义的括号分隔。您可以在这里看到,我没有费心在第二组中捕获右括号,而是选择简单地将其包含在替换中。这在这种情况下效果很好,因为它不会改变,但是如果您不知道冒号将出现在括号括起来的内容的末尾,您将需要第二组:

string.sub /(\([^:]+):([^)]+\))/, '\1\2'
于 2012-07-10T19:26:01.090 回答
1

先前的答案主要适用于删除括号组中的单个冒号,但对于像“(thing:foo:bar)”这样的倍数有问题。使用lookbehind 和lookahead 来进行inside parens 断言会很好,但是ruby(和大多数regexp 引擎)不支持lookbehind 中的非确定性长度模式。

irb> s = 'x (a:b:c) : (1:2:3) y'
=> "x (a:b:c) : (1:2:3) y"

irb> s.gsub /(?<=\([^\(]*):(?=[^\)]*\))/, ''
SyntaxError: (irb):10: invalid pattern in look-behind: /(?<=\([^\(]*):(?=[^\)]*\))/
    from /Users/dbenhur/.rbenv/versions/1.9.2-wp/bin/irb:12:in `<main>'

您可以改为使用 gsub 的块形式来捕获括号括起来的组,然后从每个匹配项中删除冒号:

irb> s.gsub(/\([^\)]*\)/) {|m| m.delete ':'}
=> "x (abc) : (123) y"
于 2012-07-10T22:04:21.197 回答
0

在一般的正则表达式中,你可以使用'(\()(:)(\))', \1\3.

我对红宝石不熟悉。基本上你要做的是你有 3 个组,从这三个组中( : and )你去掉第二个,:.

我在 Notepad++ 中对其进行了测试,并且可以正常工作。

我认为这被称为:正则表达式反向引用

干杯。

于 2012-07-10T19:12:35.630 回答
0

如果您可以假设所有括号将像您的示例中那样平衡成对出现,那么这应该就是您所需要的:

"This is a (string :)".gsub!(/:(?=[^()]*\))/, '') 

如果前瞻成功地找到了一个结束括号而没有首先看到一个开始的括号,那么冒号必须在一个(...)序列内。请注意我是如何排除开头括号和结尾括号的;这是必不可少的。

于 2012-07-11T01:54:33.463 回答