【问题标题】:split based on the last dot and create a new column with the last part of the string根据最后一个点拆分并使用字符串的最后一部分创建一个新列
【发布时间】:2021-10-25 17:37:33
【问题描述】:

我有一个包含 2 列的文件。在第一列中,有几个字符串 (ID),在第二个值中。在字符串中,有许多点是可变的。我想根据最后一个点拆分这些字符串。我在论坛中找到了如何删除最后一个点之后的最后一个过去,但我不想删除它。我想使用 bash 命令(例如 awk)使用字符串的最后一部分创建一个新列

字符串示例:

   5_8S_A.3-C_1.A   50
   6_FS_B.L.3-O_1.A 20 
   H.YU-201.D   80
   UI-LP.56.2011.A  10 

输出示例:

   5_8S_A.3-C_1 A   50
   6_FS_B.L.3-O_1   A   20 
   H.YU-201 D   80
   UI-LP.56.2011    A   10

我尝试使用以下命令来解决它,但如果我在字符串中只有 1 个点,它就可以工作:

awk -F' ' '{{split($1, arr, "."); print arr[1] "\t" arr[2] "\t" $2}}' file.txt

【问题讨论】:

  • 是的,当然.. 我尝试使用以下命令解决它,但如果我在字符串中只有 1 个点,它就可以工作: awk -F' ' ' {{split($1, arr, ".");打印 arr[1] "\t" arr[2] "\t" $2}}' file.txt

标签: awk split tabs


【解决方案1】:

你可以使用这个sed:

sed -E 's/^([[:blank:]]*[^[:blank:]]+)\.([^[:blank:]]+)/\1 \2/' file

   5_8S_A.3-C_1 A   50
   6_FS_B.L.3-O_1 A 20
   H.YU-201 D   80
   UI-LP.56.2011 A  10

详情:

  • ^:开始
  • ([[:blank:]]*[^[:blank:]]+):捕获组 #2 以匹配 0 个或多个空格,后跟 1+ 个非空格字符。
  • \.:匹配一个点。由于这个正则表达式模式是 greedy 它将匹配到最后一个点
  • ([^[:blank:]]+): 捕获组 #2 以匹配 1+ 个非空白字符
  • \1 \2:替换为在捕获值 #1 和捕获值 #2 之间放置一个空格

【讨论】:

    【解决方案2】:

    假设:

    • 每行由两个(空白)空格分隔的字段组成
    • 第一个字段至少包含一个句点 (.)

    坚持 OP 的愿望 (?) 使用 awk:

    awk '
    { n=split($1,arr,".")            # split first field on period (".")
      pfx=""
      for (i=1;i<n;i++) {            # print all but the nth array entry
          printf "%s%s",pfx,arr[i]
          pfx="."}
      print "\t" arr[n] "\t" $2}     # print last array entry and last field of line
    ' file.txt
    

    移除 cmets 并缩减为单行:

    awk '{n=split($1,arr,"."); pfx=""; for (i=1;i<n;i++) {printf "%s%s",pfx,arr[i]; pfx="."}; print "\t" arr[n] "\t" $2}' file.txt
    

    这会生成:

    5_8S_A.3-C_1    A       50
    6_FS_B.L.3-O_1  A       20
    H.YU-201        D       80
    UI-LP.56.2011   A       10
    

    【讨论】:

      【解决方案3】:

      对于您展示的示例,这里是rev + awk 解决方案的另一种变体。

      rev Input_file | awk '{sub(/\./,OFS)} 1' | rev
      

      解释: 简单的解释是,使用rev 为每一行打印相反的顺序(从最后一个字符到第一个字符),然后将其输出作为awk 程序的标准输入,其中用空格替换第一个点(仅根据 OP 显示的示例是最后一个点)并打印所有行。然后将此输出作为标准输入再次发送到rev 以按正确顺序打印输出(以消除此处 1st rev 命令的影响)。

      【讨论】:

        【解决方案4】:
        $ sed 's/\.\([^.]*$\)/\t\1/' file
        5_8S_A.3-C_1    A       50
        6_FS_B.L.3-O_1  A       20
        H.YU-201        D       80
        UI-LP.56.2011   A       10
        

        【讨论】:

        • 适用于给定的示例数据,但如果 50.8 作为第一行的最后一个值,则它可能不起作用。
        • 同意,但鉴于 OP 示例输入,情况似乎并非如此。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-04-23
        • 1970-01-01
        • 2023-03-27
        • 1970-01-01
        • 2022-01-19
        • 2013-01-02
        相关资源
        最近更新 更多