【问题标题】:How to extract phone number and Pin from each text line如何从每个文本行中提取电话号码和 Pin
【发布时间】:2021-10-28 15:24:39
【问题描述】:

日志文件中的示例文本

2021/08/29 10:25:37 20210202GL1 Message Params [userid:user1] [timestamp:20210829] [from:TEST] [to:0214736848] [text:You requested for Pin reset. Your Customer ID: 0214736848 and PIN: 4581]
2021/08/27 00:03:18 20210202GL2 Message Params [userid:user1] [timestamp:20210827] [from:TEST] [to:0214736457] [text:You requested for Pin reset. Your Customer ID: 0214736457 and PIN: 6193]
2021/08/27 10:25:16 Thank you for joining our service; Your ID is 0214736849 and PIN is 5949

其他措辞和格式可以改变,但 IDPIN 不会改变

每行的预期输出

0214736848#4581
0214736457#6193
0214736849#5949

以下是我使用 bash 尝试过的内容,但目前只能提取数值

while read p; do 

NUM='' 
counter=1;
text=$(echo "$p" | grep -o -E '[0-9]+')

for line in $text
do
if [ "$counter" -eq 1 ] #if is equal to 1
then
 NUM+="$line"  #concatenate string
 else
 NUM+="#$line"  #concatenate string
 fi
 let counter++  #Increment counter
done

printf "$NUM\n"
done < logfile.log

当前的输出虽然不是预期的。

2021#08#29#00#03#18#20210202#2#1#20210826#0214736457#0214736457#6193
2021#08#27#10#25#37#20210202#1#1#20210825#0214736848#0214736848#4581
2021#08#27#10#25#16#0214736849#5949

【问题讨论】:

  • 使用 sed:sed -n 's/.*ID: \([0-9]\+\).*PIN: \([0-9]\+\).*/\1#\2/p' file
  • 您添加了第三行输入,因为you said in a comment 那是我的答案无法正确处理的有效输入,但是您没有将该行的输出添加到预期输出中,所以我们现在很困惑。如果应该有新的第三行输入的输出,那么请edit你的问题来显示它,如果没有,那么请edit你的问题来澄清你的需求。

标签: bash awk sed grep


【解决方案1】:

使用 sed 捕获组可以做到:

sed 's/.* Your Customer ID: \([0-9]*\) and PIN: \([0-9]*\).*/\1#\2/g' file.txt

【讨论】:

    【解决方案2】:

    使用bash 和正则表达式:

    while IFS='] ' read -r line; do
      [[ "$line" =~ ID:\ ([^\ ]+).*PIN:\ ([^\ ]+)] ]]
      echo "${BASH_REMATCH[1]}#${BASH_REMATCH[2]}"
    done <file
    

    输出:

    0214736848#4581 0214736457#6193

    【讨论】:

    • 这也有效,我认为它可能会更好,因为我使用的是 bash 脚本。但是你之前发布的awk解决方案和这个,哪个消耗资源少?
    • 对于多行文件,我更喜欢awksed
    • 即使对于没有很多行的文件,awk 或 sed 也会更简洁、更清晰、更容易编写而没有任何陷阱,至少同样高效且更便携,因此我无法想到 awk 的位置或者 sed 解决方案不会像我们在这里所做的那样仅用于操作文本的 shell 循环。 @Baguma 见why-is-using-a-shell-loop-to-process-text-considered-bad-practice
    【解决方案3】:

    使用gawk 和 2 个捕获组的另一种变体,每组匹配 1 个或多个数字:

    awk '
    match($0, /ID: ([0-9]+) and PIN: ([0-9]+)/, m) {
      print m[1]"#"m[2]
    }
    ' file
    

    输出

    0214736848#4581
    0214736457#6193
    

    对于更新后的问题,如果您想要更精确的匹配,您可以匹配 : is,捕获组值将是 2 和 4。

    awk '
    match($0, /ID(:| is) ([0-9]+) and PIN(:| is) ([0-9]+)/, m) {
      print m[2]"#"m[4]
    }
    ' file
    

    输出

    0214736848#4581
    0214736457#6193
    0214736849#5949
    

    【讨论】:

    • 您的第一个答案对我来说效果更好。感谢您向我展示了解决同一问题的不同方法。
    【解决方案4】:

    对于您显示的示例,请尝试遵循awk 代码,您可以使用不同的字段分隔符简单地做到这一点。简单的解释是,将Customer ID: OR and PIN: OR ]$ 作为字段分隔符,然后记住它们只打印第二和第三字段以及 # 根据 OP 要求的输出。

    awk -v FS='Customer ID: | and PIN: |]$' '{print $2"#"$3}' Input_file
    

    【讨论】:

      【解决方案5】:

      鉴于您问题中的更新输入,然后在每个 Unix 机器上的任何 shell 中使用任何 sed:

      $ sed 's/.* ID[: ][^0-9]*\([0-9]*\).* PIN[: ][^0-9]*\([0-9]*\).*/\1#\2/' file
      0214736848#4581
      0214736457#6193
      0214736849#5949
      

      原答案:

      在每个 Unix 机器上的任何 shell 中使用任何 awk:

      $ awk -v OFS='#' '{print $18, $21+0}' file
      0214736848#4581
      0214736457#6193
      

      【讨论】:

      • 这并不能解决我的问题,因为文本是动态的。在这种情况下,只有 IDPIN 这两个词是我必须寻找的键。另一个文本的示例如下所示Thank you for joining our service; Your ID is 0214736849 and PIN is 5949
      • 它可能无法解决您真正遇到的问题,但它正在解决您告诉我们您遇到的问题。请edit您的问题包含更多真正具有代表性的示例输入和预期输出,包括我提出的脚本不起作用的情况,以便我们可以帮助您解决真正的问题。
      • 谢谢你,但重要的是我至少没有从你身上学到什么。
      • 不客气。我更新了我的答案以匹配您更新的示例输入。
      猜你喜欢
      • 2018-05-22
      • 1970-01-01
      • 2013-08-20
      • 1970-01-01
      • 1970-01-01
      • 2022-10-24
      • 1970-01-01
      • 2014-05-16
      • 1970-01-01
      相关资源
      最近更新 更多