【问题标题】:remove a line with special character with given pattern删除具有给定模式的特殊字符的行
【发布时间】:2013-12-17 11:50:40
【问题描述】:

我正在尝试获取带有不以\ 为前缀的特殊字符的行。以下是特殊字符:

^$%.*+?!(){}[]|\

我需要检查上述所有在第二列中没有以\ 为前缀的特殊字符。我正在尝试使用 awk 来完成此操作,但没有运气。我想要如下输出。

输入.txt

1,ap^ple
2,o$range
3,bu+tter
4,gr(ape
5,sm\(ok\e
6,ra\in
7,p+la\\y
8,wor\+k

输出.txt

1,ap^ple
2,o$range
3,bu+tter
4,gr(ape
5,sm\(ok\e
6,ra\in
7,p+la\\y

第 7 行和第 5 行在 output.txt 中,因为有 2 个特殊字符(一个带反斜杠,另一个不带反斜杠)

【问题讨论】:

  • 是否应该输出包含“\\\”的行?为什么?

标签: linux shell unix sed awk


【解决方案1】:

“final”最终编辑:我想允许“\x”无论 x 是什么,但 OP 似乎不希望这样,所以我也修复了它。

在尝试找到一个“聪明”的正则表达式后(它在“\\”或任何有缺陷的“\”上阻塞,但显然对其余部分有效......)

我在 awk 中重新编写了它,以“状态自动机”的方式进行:

想法:

如果在“正常模式”下,我们会遇到“\”以外的特殊字符? : 我们打印线! 如果在“正常模式”,我们会遇到一个“\”? :我们进入“转义模式”,在该模式下,忽略下一个字符 (但如果我们没有下一个字符,我们也需要打印该行!)

脚本:

awk -F"," '
  {
    IN_ESCAPED_MODE=0 ;
    for (i=1 ; i<=length($2) ; i++)
     {  char=substr($2,i,1)

        if ( IN_ESCAPED_MODE == 0)
     {  if ( index(".^$%*+?!(){}[]|",char) > 0 )
             {  print $0 ; break ;
             }

            if ( index("\\" , char ) > 0 )
             {  IN_ESCAPED_MODE=1 ; continue ;
             }
         }

        if ( IN_ESCAPED_MODE == 1)
     {   if ( index(".^$%*+?!(){}[]|\\",char) > 0 )
           {  IN_ESCAPED_MODE=0 ; continue ;
               }
             else
               {  IN_ESCAPED_MODE=0 ; print $0; break;
               }
         }
     }

    if (IN_ESCAPED_MODE == 1)
     {
        print $0 ; break ;
     }

  }
'  input.txt > output.txt

通过此更改,您将获得与 OP 相同的输出,例如,当它包含“\e”时会打印一行...我觉得很奇怪:对我来说“\e”很好,我们可以“逃”什么?

使用该输入:

1,ap^ple
2,o$range
3,bu+tter
4,gr(ape
5,sm\(ok\e
6,ra\in
7,p+la\\y
8,wor\+k

10,\
11,\\
12,\\\
13,.
14,\.
15,..
16,^
17,\^
18,$
19,\$
20,%
21,\%
22,*
23,\*
24,+
25,\+
26,?
27,\?
28,!
29,\!
30,(
31,\(
32,)
33,\)
34,{
35,\{
36,}
37,\}
38,[
39,\[
40,]
41,\]
42,|
43,\|

它输出:

1,ap^ple
2,o$range
3,bu+tter
4,gr(ape
5,sm\(ok\e
6,ra\in
7,p+la\\y
10,\
12,\\\
13,.
15,..
16,^
18,$
20,%
22,*
24,+
26,?
28,!
30,(
32,)
34,{
36,}
38,[
40,]
42,|

(看来这次真的有效!)

如果您更愿意允许 any "\x" 而不仅仅是 "x" 是一个特殊字符:

改变“中间线”:

        if ( IN_ESCAPED_MODE == 1)
         {  if ( index(".^$%*+?!(){}[]|\\",char) > 0 )
             {  IN_ESCAPED_MODE=0 ; continue ;
             }
            else
             {  IN_ESCAPED_MODE=0 ; print $0; break;
             }
         }

进入:

        if ( IN_ESCAPED_MODE == 1)
         {  IN_ESCAPED_MODE=0 ; continue ;
         }

由于历史原因:正则表达式(在“大多数”情况下有效,但在某些情况下会阻塞,例如如果有“\\”):

 egrep '[^\][].^$%*+?!(){}[|]|[^\][\][^].^$%*+?!(){}[|\]'   input.txt > output.txt

但是那个不会显示第 12 行,例如...

很好读:http://www.regular-expressions.info/charclass.html .... 和 http://www.gnu.org/software/gawk/manual/html_node/Gory-Details.html(可怕...)

【讨论】:

  • sed输出和input.txt一样
  • 仍然没有区别,我可以在 output.txt 中看到 8,wor\+k
  • 啊,是的,我没有考虑到:“\”后跟一个特殊的字符! (因此,我的版本看到“\”并认为它是一个“\”,在它之前没有适当的“\”......所以它打印出该行)。谢谢,很好的收获。我会努力解决的。
  • 已修复。我希望...(可能有特殊情况,可能会出现奇怪的“\”)
  • 嗯,案例“d”是错误的......有趣。我需要弄清楚如何在“[]”中添加“]”来修复它
【解决方案2】:

您可以尝试以下方法:

awk '
{
    line=$0
    sub(/\\[\^$%.*+?!(){}\[\]|\\]/,"")
    if(/[\^$%.*+?!(){}\[\]|\\]/)
        print line
}' input.txt

【讨论】:

    【解决方案3】:
    sed '/[]\\^$%.*+?!(){}[|]/ {
      h
      s/\\[]\\^$%.*+?!(){}[|]/_/g
      /[]\\^$%.*+?!(){}[|]/ {
        x
        p
        }
      }' YourFile
    

    根据 shell 和 sed 的不同,可能会有不同的解释(尤其是 \)。在我的 AIX/KSH 上工作

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多