1

我正在尝试编写正则表达式来匹配不在引号内的字符串(双引号或单引号),但到目前为止我能做的最好的事情是循环遍历字符串的所有字符。必须有一个更简单、更优雅的解决方案。

示例:如果尝试foobar字符串替换hello foo!将变为hello bar!,但字符串you said "my name is foo"将保持不变。

任何人都可以帮助使用正则表达式来实现上述目标吗?

4

3 回答 3

3

一种方法,使用负前瞻:

perl -lane 's/foo(?![^"]*"(?:[^"]*"[^"]*")*[^"]*$)/bar/g; print' input

这意味着如果前面的引号数量不是奇数,则替换。所以这个假设你在输入中有平衡的引号。

示例输入:

hello foo!
"foo" foo "foo"
foo "hello" foo
"foo" bar

示例输出:

hello bar!
"foo" bar "foo"
bar "hello" bar
"foo" bar
于 2013-10-05T07:42:10.567 回答
0

也需要这样做,所以自己解决了......这个解决方案不依赖平衡引号,但如果它们成对出现,显然不支持撇号。

#!/usr/bin/perl

my @test = ( 'hello foo!',
             '"my name is foo"',
             'foo test "test foo test" test foo test "test foo test" test foo',
             "foo test 'test foo test' test foo test 'test foo test' test foo",
             '"foo test foo"',
             'foo test " foo test' );

foreach ( @test )
{
  s!("[^"]*"|'[^']*')|foo!$1//'bar'!ge;
  print "$_\n";
}
于 2015-03-10T00:33:11.123 回答
0

更新:快速总结:虽然你需要“平衡组”来真正处理这个问题,但简短的回答是,如果你也需要单引号,你就不能这样做。因为那些兼作撇号。所以无论如何,这真的会让你大吃一惊:That's when foo said, "That's my line!"平衡会被撇号搞得一团糟。您需要构建一个自定义解析引擎。

注意:如果这是用于 HTML 属性...我已经编写了一个正则表达式,可以完全按照您的说法正确解析它们,并且我相信它可以在 Perl 中工作。但这也依赖于=符号和其他 HTML 结构等分隔符。但在 90% 的情况下,XML/HTML 解析器是最好的选择(那 10% 仍然是可能的)。

正如我在对您的问题的评论中提到的那样,更多的例子会给出更具体的答案。这是您有限示例的答案:

^([^"']*?)foo([^"']*)$

对于中级正则表达式编写者来说,环顾四周很容易,但对于代码维护来说很复杂,而且通常不是所需要的。此外,任何需要您.在正则表达式中使用点的东西通常都没有它可能的效率。

替换我的例子,$1bar$2你会很成功。但是,正如我的评论所说,这是基于您的基本示例,假设您的整个字符串可能以引号开头和结尾。如果你有不同的例子,他们会有所帮助。

添加

只是为了好玩,我将回答您的其他两个选项的问题。选项1是我上面的原始答案。

选项 2(如 Floris 所述):

Hi foo, I said "hello"

或者

"hello", said foo to his friend.

如果是这种情况,引用的文本只会出现在您的搜索文本之前或之后(在这种情况下为 foo),那么答案是这样的:

^(?:([^"']*?)foo(.*)|(.*?)foo([^"']*))$

选项 3(见我下面的评论)

He said, "Hello", so then Foo told him, "Lawl, bye"

为此,我们必须计算 foo 之前和之后的 Quotes 数量,以确保它们是偶数,或者它们在 .NET Regex 中“关闭”称为“Balancing”,这两个选项都不可用在您的情况下,没有其他一些自定义功能。

于 2013-10-05T04:24:14.423 回答