【问题标题】:split strings containing piping characters拆分包含管道字符的字符串
【发布时间】:2013-06-09 10:07:10
【问题描述】:

我正在处理一些包含“||||”的字段分隔符的文本:

substring1||||substring2

子字符串也可能包含空格。我想根据分隔符“||||”拆分这些字符串,但我找不到合适的方法来做到这一点。 我尝试了以下命令:

echo "substring1||||substring2" | awk '{split($0,a,"||||"); a[2],a[1]}'

实际上,如果我只有一个“|”,则该命令有效作为分隔符。但我的问题是我有多个管道字符。

我也试过了

a=($(echo "substring1||||substring2" | sed -e "s/||||/\n/g")) 

如果子字符串不包含空格,它可以正常工作。但由于子字符串可能包含空格,因此它们也会在空格上进行拆分,这是不希望的。

有什么想法吗?

【问题讨论】:

    标签: linux bash text sed awk


    【解决方案1】:

    使用正则表达式作为输入字段分隔符,例如:

    awk -F'[|]{4}' '{ printf "Field 1 -> %s\nField 2 -> %s\n", $1, $2 }' infile
    

    假设infile有内容:

    sub string 1||||sub string2
    

    它产生:

    Field 1 -> sub string 1
    Field 2 -> sub string2
    

    编辑:对于不接受 {n} 语法的旧 awk 版本,请改用 -F'[|][|][|][|]'-F'[|]+',例如:

    awk -c -F'[|]+' '{ printf "Field 1 -> %s\nField2 -> %s\n", $1, $2 }' infile
    

    另外添加--re-interval,感谢blue的评论:

    awk -c --re-interval -F'[|]{4}' '{ printf "Field 1 -> %s\nField2 -> %s\n", $1, $2 }' infile 
    

    【讨论】:

    • @Hakim:也许你的awk 版本太旧了,但你是对的。似乎它不接受 {n} 语法,因为我用 -F'[|][|][|][|]' 摆脱了它并且它有效。试一试。
    • 谢谢Birei,这个很好用。也可以使用 -F'[|]+' 而不是重复 4 次。
    • @Hakim:是的。这也有效。我已经编辑了答案以添加两个选项。
    • 有没有办法将结果存储在数组中而不是打印出来?实际上我想在一个数组中有第一列,在另一个数组中有第二列。处理完成后,将它们存储在 2 个单独的文件中。
    • 在 gawk 中,您必须添加选项 --re-interval 才能使用像 {4} 这样的乘数
    【解决方案2】:

    使用GNU awk,您可以描述使用FPAT 的字段,而不是描述字段分隔符是什么:

    $ echo "substring1||||substring2" | awk '{print $1,$2}' FPAT='[^|]+' OFS='\n'
    substring1
    substring2 
    

    【讨论】:

    • +1。我不知道这个 awk 功能。但这会使用嵌入的“|”或“||”或“|||”拆分字段
    【解决方案3】:

    splitawk 中使用的模式实际上是正则表达式,所以|||| 实际上可能是 4 个交替运算符而不是 4 个文字竖线(我不确定,因为在某些条件下,| 可以一个文字竖线。

    要匹配竖线,请使用\|[|]。所以对于你想要的,你可以这样做

    awk '{ split($0, a, /\|+/); print a[2],a[1]}' file
    

    注意我使用/.../(正则表达式常量)而不是引号(动态正则表达式)来包围模式。关于gawk manual的区别的一些细节。


    如果你想把第一列写到一个文件,第二列写到另一个文件,你可以在awk中全部完成(我用的是Birei的方式,因为它更简洁)。

    awk -F'[|]+' '{c1 = c1 $1 "\n"; c2 = c2 $2 "\n"} END {printf c1 >"file1"; printf c2 >"file2"}' input_file
    

    这会将第 1 列条目附加到 c1,并用换行符分隔,第 2 列附加到 c2。然后在处理输入文件后将两者打印到单独的文件中。

    注意事项:

    1. 通过将字符串并排放置,在awk 中进行连接。
    2. 我使用了printf,它不附加换行符,因为我们已经在c1c2 的末尾多了一个换行符。
    3. awk 脚本中除printf 及其参数之间的所有水平间距都是可选的。

    旁注:-F 的值实际上是一个动态正则表达式,所以'[|]+' 的等价物是'\\|+'

    【讨论】:

      【解决方案4】:

      尝试使用 sed 和 tr ...看看是否有帮助!

      Input.txt

      sub string 1||||sub string 2
                  or
       substring1||||substring2
      

      代码

        sed 's/||*/%~%/g' Input.txt| tr "%~%" '\n' | sed '/^$/d'
      

      注意

      使用任何表达式,如 "%~%" ...。任何不会出现在您的文本文件中的表达式(如我使用过的)...并使用 sed 和 tr 替换它...

      【讨论】:

      • 我不能用分号替换管道字符,因为子字符串可能包含分号并且可能导致错误的拆分。
      • 已更新 ... 只需替换 ';'与其他不会出现在您的文本文件中的表达式......
      猜你喜欢
      • 2011-04-20
      • 1970-01-01
      • 1970-01-01
      • 2014-02-13
      • 2019-06-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多