是否有更强大的方法来编辑匹配的模式,然后替换它?

是否有更强大的方法来编辑匹配的模式,然后替换它?

有没有办法编辑匹配的模式,然后用编辑后的模式替换另一个模式?

输入:

a11.t
some text here
a06.t
some text here

输出:

a11.t 11
some text here
a06.t 06
some text here

上面的示例显示了提取的前两个数字(与第一个模式匹配)并放置在行的末尾(第二个模式)。

在编程语言中,我会将文件加载到数据结构中,编辑、替换并写入新文件。但是否有等效的单行代码呢?

审判:

sed 's/\(a[0-9][0-9].*\)/& \1/I' stack.fa | sed -e 's#a##g2' -e 's#\.\w##g2'

试验输出:

a11.t 11
some text here
a06.t 06
some text here

显然试验是有效的,但是有没有更稳健的方法呢?此外,是否有另一种文本处理语言可以更轻松地完成此任务?

答案1

尽管它已经过时了,但很少有语言可以与 perl 进行文本处理相媲美。例如:

  1. 假设只有一组数字,复制到行尾:

     $ perl -pe 's/.*?a(\d+).*/$& $1/' file
     a11.t 11
     some text here
     a06.t 06
     some text here
    
  2. 多组数字,将两者相加到最后

     $ cat file
     a11.t
     some text here
     a06.t
     some text here
     a11.t a54.g
    
     $ perl -pe '@nums=(/a(\d+)/g); s/$/ @nums/' file
     a11.t 11
     some text here 
     a06.t 06
     some text here 
     a11.t a54.g 11 54
    

答案2

sed这是完成这项任务的完美工具。但请注意,您几乎不需要将多个sed调用连接在一起,因为sed脚本可以由多个命令组成。

如果您想提取第一个 2 个十进制数字序列,并在找到后在行尾添加一个空格,您可以这样做:

sed 's/\([[:digit:]]\{2\}\).*$/& \1/' < your-file

如果您只想在该行的第二个位置找到它并跟随 a 时才执行此操作a

sed 's/^a\([[:digit:]]\{2\}\).*$/& \1/' < your-file

如果您不想这样做,如果该 2 位数字序列后面跟着更多数字:

sed 's/^a\([[:digit:]]\{2\}\)\([^[:digit:]].*\)\{0,1\}$/& \1/' < your-file

按照鲁棒性这一切都归结为回答这个问题:应该搭配什么?不应该是什么?。这就是为什么明确指定您的要求并了解输入可能是什么样子(例如行中是否有您不想找到匹配项的数字?,输入中可以有非 ASCII 字符吗?,输入是否以语言环境的字符集进行编码?ETC。)。

上面,根据实现sed,输入将根据区域设置的字符映射被解码为文本(请参见 的输出locale charmap),或者解释为每个字节对应一个字符,并且字节 0 到 127 根据 ASCII 字符映射解释(假设您'不在基于 EBCDIC 的系统上)。

对于sed第一类的实现,如果文件未使用正确的字符集进行编码,则可能无法正常工作。对于第二类,如果输入中存在编码包含十进制数字编码的字符,则可能会失败。

答案3

最简单的方法是通过以下方式:

$ perl -lne '$,=$"; print $_, /a(\d+)/' file
# or this 
$ perl -lpe 's/a(\d+).*\K/ $1/' file
$ awk '
    match($1, /^a[[:digit:]]+/) &&
    gsub(/$/, FS substr($1, RSTART+1, RLENGTH-1)) ||
  1' file

substr注意:在 的替换部分中使用是安全的,gsub因为我们已经确保它是纯数字的。

答案4

perl或者是要走的路,但只是为了完成,使用 module的匹配“组”概念sed重写 @PraveenKumarBS 的 python 片段的第一个版本:re

#!/usr/bin/python3
import re
pattern = re.compile(r'(\d{2})')
with open('data', 'r') as file:
    for line in file:
        match = re.search(pattern, line)
        if match:
            print(line.rstrip('\n'), match.group(1))
        else:
            print(line.rstrip('\n'))

如果OP似乎暗示要查找的模式始终包含第一个字母,则只需将模式设置为:pattern = re.compile(r'[a-zA-Z](\d{2})')

match = re.finditer(pattern, line)使用新的匹配表达式和修改后的指令也可以轻松处理每行多个匹配的角(?)情况(如@terdon 所述)print

相关内容