bash 0 个子字符串上的填充数字

bash 0 pad numbers on substrings

我有一长串如下:

D6N
T69TN
K70R
M184V
T215FEG

结果一定是这样的:

D006N
T069TN
K070R
M184V
T215FEG

我是 bash 的新手,我尝试了基于将其拆分为多列并重新格式化的方法。然而,第二和第三假定列的位置和长度不固定。 感谢您的帮助!

sed 的正则表达式有点长,但这里是 Perl:

echo "D6N" | perl -pe 's/(\D)(\d)(\D)/0/g; s/(\D)(\d\d)(\D)/0/g;'

它会用非数字包围的 1 位和 2 位数字填充零。它用一个简单的技巧来做到这一点:用一个零填充 1 位数字(因此 1 位数字变成 2 位数字),然后用另一个零填充 2 位数字。

AFAIK,对此没有简单的纯Bash 解决方案。所以,我更喜欢Perl,因为Perl的表达很简洁,而且Perl无处不在。

s='D6N
T69TN
K70R
M184V
T215FEG'

echo "$s" | perl -ne '/^(\D*)(\d{1,2})(\D*)$/m and printf "%s%03s%s", , ,  or print'

您可以使用 awk 执行此操作,使用内置的 match 函数:

awk 'match([=10=], /[0-9]+/) { printf "%s%03d%s\n", 
substr([=10=], 0, RSTART - 1), substr([=10=], RSTART, RLENGTH), substr([=10=], RSTART + RLENGTH) }' file

match成功时,设置了两个变量RSTARTRLENGTH,可以用来提取子串。中间的子字符串使用 %03d 格式化,用前导零填充。

任何与模式不匹配的行都不会被打印。

另一个使用 perl 的选项:

perl -pe 's/\d{1,3}/sprintf("%03d", $&)/eg' file

这会将任何一到三位数字的序列替换为零填充的三位数字。在此版本中,打印所有行。

另一个基于 sed 的实现:

$ cat testfile
D6N
T69TN
K70R
M184V
T215FEG

$ sed -r 's/[0-9]+/00&/g; s/0?0?([0-9]{3})//g' testfile
D006N
T069TN
K070R
M184V
T215FEG

逻辑:无条件地在数字前加 2 个零并删除前导零,直到数字长为 3 位。

这个gnu awk也能搞定:

awk -v RS='[0-9]+' 'RT{print [=10=] sprintf("%03d", RT); next} 1' ORS= file

D006N
T069TN
K070R
M184V
T215FEG

使用 Bash 正则表达式:

#!/bin/bash

re='([[:alpha:]]*)([[:digit:]]*)([[:alpha:]]*)'

while IFS= read -r line; do
    [[ $line =~ $re ]]
    printf "%s%03d%s\n" "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}"
done < infile

这会将每一行与正则表达式匹配并捕获三组:字母、数字、字母。 printf 格式字符串确保数字组在短于三位数字时用零填充。