在一行上打印字符串中的 2 个不同模式

在一行上打印字符串中的 2 个不同模式

我有一个包含如下字符串的文件。

F1B308F2B3094F3B310F4B317CF5B312F6BC313DF7B315

字符串由标记(在本例中为“F”和数字)划分。在本例中,标记为F1, F2, F3, F4, F5,F6F7

我想打印后面的 5 个字符F2和后面的 6 个字符,F6并用空格分隔,以便结果是

B3094 BC313D

这是我的尝试,尽管它打印成两行而不是一行。如何将两个值都放在一行上。

$ echo F1B308F2B3094F3B310F4B317CF5B312F6BC313DF7B315 | \
   awk '{match($0,/F2/); print substr($0, RSTART +2, RLENGTH +3);} \
        {match($0,/F6/); print substr($0, RSTART +2,RLENGTH +4);}'

答案1

您非常接近可行的解决方案。这是一种方法(为了便于阅读而格式化):

awk '{
    match($0,/F2/); 
    a=substr($0, RSTART +2, RLENGTH +3); 
    match($0,/F6/); 
    b=substr($0, RSTART +2,RLENGTH +4);
    print a" "b
}'

在本例中,我将采用您的两个substr()函数并将它们分配给变量,而不是直接打印它们,然后将它们设置为在最后同时打印。通过在单个打印调用中打印它们,awk仅在行尾添加一个换行符,而不是在该行的每个部分之后添加,这就是将结果分成两行的原因。

bash:~$ echo F1B308F2B3094F3B310F4B317CF5B312F6BC313DF7B315 | awk '{match($0,/F2/); a=substr($0, RSTART +2, RLENGTH +3); match($0,/F6/); b=substr($0, RSTART +2,RLENGTH +4); print a" "b}'
B3094 BC313D

答案2

如果您知道标记是有序的,那么您可以将它们用作字段分隔符:Fn

echo 'F1B308F2B3094F3B310F4B317CF5B312F6BC313DF7B315' | 
    awk -F'(F2|F6)' '{print substr($2,1,5), substr($3,1,6)}'
B3094 BC313D

或者,拆分所有标记并对字段进行相应编号Fn

echo 'F1B308F2B3094F3B310F4B317CF5B312F6BC313DF7B315' | 
    awk -F'F[0-9]' '{print substr($3,1,5), substr($7,1,6)}'
B3094 BC313D

(在这种情况下,substr如果您只想要下一个的所有内容,您可能根本不需要- 从您的问题描述中不清楚)。Fn

使用 GNU Awk,您可以捕获单个模式中的两个子字符串并通过可选match数组访问它们:

echo 'F1B308F2B3094F3B310F4B317CF5B312F6BC313DF7B315' | 
    gawk 'match($0, /F2(.{5}).*F6(.{6})/, a) {print a[1], a[2]}'
B3094 BC313D

或者,使用 Perl,您可以使用后向捕获标记后的字符:

echo 'F1B308F2B3094F3B310F4B317CF5B312F6BC313DF7B315' | 
    perl -lne 'print join " ", /(?<=F2).{5}|(?<=F6).{6}/g'
B3094 BC313D

或者

echo 'F1B308F2B3094F3B310F4B317CF5B312F6BC313DF7B315' | 
    perl -lne 'print "$1 $2" if /(?<=F2)(.{5}).*?(?<=F6)(.{6})/g'
B3094 BC313D

答案3

perl -lne ' $, = $"; print /(?=.*F2(.{5}))(?=.*F6(.{6}))/' input-file.txt

无论哪个,F2或者F6在当前记录中出现得更早,F2上面的内容都将打印 的以下数字F6

$, = OFS $" = double quoted separator = single space

相关内容