2016-04-22 57 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可確保數字組的長度小於三位數字時爲零填充。