【问题标题】:Regex for whitespace delemiter except for [ and ] characters除 [ 和 ] 字符外的空白分隔符的正则表达式
【发布时间】:2021-12-26 15:38:54
【问题描述】:

我认为我自己在正则表达式方面做得很好,但是这个似乎出奇的棘手。

我想修剪所有空格,除了 "" 和 [] 字符之间的空格。

我使用了这个正则表达式 ("[^"]*"|\S+)\s+,但确实将我的日志的 [06/Jan/2021:17:50:09 +0300] 部分分成了两个块。

这是我的整个日志行:

[06/Jan/2021:17:50:09 +0300] "" 10.139.3.194 407 "CONNECT clients5.google.com:443 HTTP/1.1" "" "-" "" 4245 75 "" "" "81" ""

结果我使用 sed 命令基于我的正则表达式(用逗号替换空格):

[06/Jan/2021:17:50:09,+0300],"",10.139.3.194,407,"CONNECT clients5.google.com:443 HTTP/1.1","","-","",4245,75,"","","81",""

终于得到了我想要的结果:

[06/Jan/2021:17:50:09 +0300],"",10.139.3.194,407,"CONNECT clients5.google.com:443 HTTP/1.1","","-","",4245,75,"","","81",""

【问题讨论】:

    标签: regex linux awk sed gnu-sed


    【解决方案1】:

    由于这些样本输入看起来像日志,因此考虑到它们将始终采用相同的格式;有了这个,您可以尝试遵循awk 代码,在 GNU awk 中显示的示例中编写和测试。

    awk -v FPAT='[^]]*\\]|"[^"]*"|([0-9]+\\.){3}[0-9]+|[0-9]{2,4}' -v OFS="," '{$1=$1} 1'  Input_file
    

    解释:

    • 简单的解释是在这里使用 GNU awk。其中有 FPAT 选项可用。
    • 以正则表达式形式设置字段分隔符的选项。它根据 FPAT 中提到的正则表达式匹配事物,并相应地为每行创建字段。
    • 然后将OFS(输出字段分隔符)设置为, 也适用于所有行。
    • awk 的主程序中重置行(通过重置第一个字段)根据 OP 的要求对其应用 OFS 值。这将确保逗号应仅根据需要输出。

    正则表达式的解释:

    [^]]*\\]               ##Matching everything till ] followed by ] here.
    |                      ##OR
    "[^"]*"                ##Matching from " till first occurrence of " everything between them including "
    |                      ##OR
    ([0-9]+\\.){3}[0-9]+   ##Matching digits followed by dot 3 times followed by digits
    |                      ##OR
    [0-9]{2,4}             ##Matching 2 to 4 digits here.
    

    【讨论】:

      【解决方案2】:

      您可以通过添加 \[[^][]*] 来匹配方括号之间的字符串作为第 1 组模式的替代方案:

      sed -E 's/(\[[^][]*]|"[^"]*"|\S+)\s+/\1,/g'
      

      现在,POSIX ERE(使用-E 选项启用语法)模式匹配

      • (\[[^][]*]|"[^"]*"|\S+) - 第 1 组:要么
        • \[[^][]*] - 一个[ 字符,然后是除[] 之外的零个或多个字符,然后是] 字符
        • |
        • "[^"]*" - 一个" 字符,零个或多个除" 之外的字符,然后是" 字符
        • | - 或
        • \S+ - 一个或多个非空白字符
      • \s+ - 一个或多个空格

      online demo

      #!/bin/bash
      s='[06/Jan/2021:17:50:09 +0300] "" 10.139.3.194 407 "CONNECT clients5.google.com:443 HTTP/1.1" "" "-" "" 4245 75 "" "" "81" ""'
      sed -E 's/(\[[^][]*]|"[^"]*"|\S+)\s+/\1,/g' <<< "$s"
      

      输出:

      [06/Jan/2021:17:50:09 +0300],"",10.139.3.194,407,"CONNECT clients5.google.com:443 HTTP/1.1","","-","",4245,75,"","","81",""
      

      【讨论】:

      • 我建议将 现在,POSIX ERE... 改写为 现在,GNU sed ERE... 使用 POSIX 形式的字符类。否则 POSIX sed 用户可能会感到困惑,为什么您的好解决方案不适合她。
      • @dawg 我为问题添加了gnu-sed 标签,因为很明显 OP 使用 GNU sed。这个上下文就足够了。
      猜你喜欢
      • 2016-02-07
      • 2021-12-27
      • 1970-01-01
      • 2021-07-11
      • 1970-01-01
      • 1970-01-01
      • 2015-07-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多