2016-04-22 49 views
1

我有很长的列表如下:庆典0键盘的数字

 
D6N 
T69TN 
K70R 
M184V 
T215FEG 

的结果必须是这样的:

 
D006N 
T069TN 
K070R 
M184V 
T215FEG 

我在bash中新,我试图总部设在分裂的方法它在列和重新格式化。然而,第二和第三推定列的位置和长度并不固定。 谢谢你的帮助!

+1

你如何构建和打印你的“清单”? “列表”从哪里来?也许Bash本身不是正确的工具,但awk或sed可能是? –

+0

同意,bash是一个shell,而不是数据处理器,所以使用像awk,sed,grep等其他工具很可能会变得异常 – edhurtig

+1

@ user3829806你的行总是使用'​​( [AZ] +)([0-9] +)([AZ] +)',你会一直需要填充最大数字的长度......即数字可能超过3位数? – edhurtig

回答

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 

这取代的一至三个数字的任何序列具有零填充三位数。在这个版本中,所有行都被打印出来。

+0

呵呵,我喜欢perl的一个......用'/ e'聪明的工作:-) – anishsane

+0

的确,perl版本工作的很快很顺利!谢谢。 – user3829806

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位数字),然后用另一个零填充2位数字。

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' 
+0

虽然这个代码可能回答这个问题,但提供 关于_why_和/或_how_的附加上下文会回答 这个问题会显着改善它的长期 值。请[编辑]你的答案,添加一些解释。 –

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个0到号码&移除前导零,直到数为3位长。

0

这GNU AWK也可以完成这项工作:

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

D006N 
T069TN 
K070R 
M184V 
T215FEG 
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可确保数字组的长度小于三位数字时为零填充。