1

我有很长的清单如下:

D6N
T69TN
K70R
M184V
T215FEG

结果必须是这样的:

D006N
T069TN
K070R
M184V
T215FEG

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

4

6 回答 6

2

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

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

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

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

使用 perl 的另一个选项:

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

这将用零填充的三位数替换任何一到三位数的序列。在这个版本中,所有行都被打印出来。

于 2016-04-22T09:34:49.653 回答
0

的正则表达式稍微长一点sed,但这里是Perl

echo "D6N" | perl -pe 's/(\D)(\d)(\D)/${1}0$2$3/g; s/(\D)(\d\d)(\D)/${1}0$2$3/g;'

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

于 2016-04-22T09:22:31.953 回答
0

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", $1, $2, $3 or print'
于 2016-04-22T09:28:59.753 回答
0

另一个sed基于实现:

$ cat testfile
D6N
T69TN
K70R
M184V
T215FEG

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

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

于 2016-04-22T10:07:35.233 回答
0

这个 gnu awk 也可以完成工作:

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

D006N
T069TN
K070R
M184V
T215FEG
于 2016-04-22T10:57:32.660 回答
0

使用 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数字组短于三位数,则用零填充。

于 2016-04-22T14:06:17.160 回答