Grep 双引号和单引号内的字符串

Grep 双引号和单引号内的字符串

我想在文本文件中找到双引号或单引号内的字符串(文本文件是多行),

例如:

I have a 
test "foo bar1" test2 "foo\"bar2", 
"foo 'bar3", 
'foo bar4', 'foo \'bar5', 'foo "bar6',

它将输出

foo bar1
foo\"bar2
foo 'bar3
foo bar4
foo \'bar5
foo "bar6

难点是:

  1. 文本文件是多行的。
  2. 它可能在引号内转义了双引号或单引号。
  3. 双引号内可以有单引号。
  4. 单引号里面可以有双引号。
  5. 引号必须成对匹配。

答案1

我们可以使用 Perl 的匹配时间代码插值功能(??{ match time regex })来解决这个问题。本质上,它的作用是,根据匹配的引用,将相应的有效正则表达式放置在该引用中,以便正则表达式引擎将捕获该引用对。

$ perl -lne '
    print substr($&, 1, -2+length($&))
      while
         /(?:(["'\''])(??{q<(?:[^\\\\>.$1.q<]|\\\\.)*>.$1}))/gx;
' file

结果:

foo bar1
foo\"bar2
foo 'bar3
foo bar4
foo \'bar5
foo "bar6

上面的更平滑的重写如下:

$ perl -lne '
    BEGIN {
       $genRE = sub {
          my $openingQ = shift;
          # look in the Notes below for why
          qq<(?:[^\\\\${openingQ}]|\\\\.)*>
       };
    }
    print $2
      while 
        /
         (["'\''])               (?#: opening quote) 
          ((??{ $genRE->($1) })) (?#: run of in between quote pair stuff) 
         \1                      (?#: corresponding closing quote)
        /gx;
' file

笔记::

  • "........"匹配的是/"[^"]*"/
  • "...... \"......"匹配的是/"(?:[^\\"]|\\.)*"/
  • 单引号也类似。

答案2

另一种perl方法:

perl -lne 'print $2 while m{(["'\''])((?:\\.|(?!\1).)*+)\1}g'

这里使用负向前看运算符来(?!\1).匹配除第一个捕获组所匹配的字符之外的字符。您还可以简单地分别覆盖'...'"..."案例:

perl -lne 'print $1 while m{(?|"((?:\\.|[^"])*+)"|'"'((?:\\\.|[^'])*+)')}g"

答案3

这是困难的。我没有解决办法。我什至不确定完成这项任务的最佳工具是什么。

我已经接近了:

$ grep -oP '((?<!\\)"\K.*?(?=(?<!\\)"))|'"((?<!\\\\)'\K.*?(?=(?<!\\\\)'))" input

foo bar1
foo\"bar2
foo 'bar3
foo bar4
, 
foo \'bar5
, 
foo "bar6

每行多个匹配的问题在于,较早字符串的结束引号与中间文本的起始引号相匹配。我不能用偶数个引号的正后视来阻止它,因为后视必须具有固定的长度。至少对于grep.

'此外,至少可以说,内部的几个匹配"(或相反)很有趣。

也许awk是更好的工具。有了它,您可以检查哪种引用类型最先出现,跳到下一个并检查它前面是否有反斜杠。

相关内容