ไม่ต้องสนใจตัวเลขที่ไม่ใช่หลักที่เป็นไปได้ที่ส่วนท้ายของตัวเลขในการแทนที่ sed

ฉันต้องเติมสตริงด้วยศูนย์จนกว่าจะถึงขีดจำกัดสี่หลัก ตัวอย่างเช่น:

1 -> 0001
44 -> 0044
555 -> 0555
1a -> 0001a
44b -> 0044b
565c -> 0565c
7890 -> 7890

ฉันมีสคริปต์ทุบตีและฉันเพิ่มไฟล์ที่มีตัวเลขเหล่านั้นเป็นพารามิเตอร์

#!/bin/bash

FILE=$1
if [ ! -f $FILE ]; then
    exit 1
fi

sed -i 's/\<[0-9]\>/0&/g' $FILE
sed -i 's/\<[0-9][0-9]\>/0&/g' $FILE
sed -i 's/\<[0-9][0-9][0-9]\>/0&/g' $FILE

สคริปต์ไม่ทำงานบน 1a, 44b, 565c ฉันไม่รู้วิธีที่จะเพิกเฉยต่อตัวอักษร


person Mr. Kevin    schedule 27.09.2017    source แหล่งที่มา
comment
\> ตรงกับขอบเขตของคำ: 1a ถือเป็นคำเดียว   -  person Andrea Corbellini    schedule 28.09.2017
comment
ฉันไม่เห็นด้วยกับการหลอกลวงของ @ funky-future คำถามนั้นเกี่ยวกับการใช้ printf นี่เป็นเรื่องเกี่ยวกับ sed ในทั้งสองกรณีผู้ถามคำถามรู้วิธีทำการเติมอยู่แล้วและกำลังมีปัญหากับการใช้งาน   -  person Will Barnwell    schedule 28.09.2017
comment
คุณสามารถให้บรรทัดอินพุตทั่วไปได้หรือไม่? สามารถมีตัวเลขดังกล่าวหลายหมายเลขต่อบรรทัดได้หรือไม่?   -  person xhienne    schedule 28.09.2017
comment
ยินดีต้อนรับสู่ Stack Overflow! กรุณาอย่าทำลายกระทู้ของคุณ ด้วยการโพสต์บนเครือข่าย Stack Exchange คุณได้ให้สิทธิ์ที่ไม่สามารถเพิกถอนได้สำหรับ SE ในการเผยแพร่เนื้อหานั้น (ภายใต้ ใบอนุญาต CC BY-SA 3.0) ตามนโยบายของ SE การก่อกวนใดๆ ก็ตามจะกลับคืนมา หากคุณต้องการยกเลิกการเชื่อมโยงโพสต์นี้จากบัญชีของคุณ โปรดดูที่ เส้นทางที่เหมาะสมสำหรับคำขอยกเลิกการเชื่อมโยงคืออะไร   -  person Suraj Rao    schedule 28.09.2017


คำตอบ (4)


GNU awk จะเป็นเครื่องมือที่ดีกว่าที่นี่:

awk -i inplace 'match($1,/([0-9]*)(.*)/,arr){$1=sprintf("%04d%s",arr[1],arr[2])}1' input.txt

ซึ่งเพิ่มตัวเลข $1 ถึง 4 หลัก

การทดสอบ:

$ cat input.txt
1
44
555
1a
44b
565c
7890

awk 'match($1,/([0-9]*)(.*)/,arr){$1=sprintf("%04d%s",arr[1],arr[2])}1' input.txt
0001
0044
0555
0001a
0044b
0565c
7890

สมมติว่าข้อมูลถูกเรียงลำดับเหมือนในคำตอบของ @ xhienne จากนั้นเราจะวนซ้ำฟิลด์:

$ cat input.txt
1 44 555 1a 44b 565c 7890 77777

$ cat tst.awk
{ for (i=1;i<=NF;i++)
    if (match($i,/([0-9]*)(.*)/,arr))
      $i=sprintf("%04d%s",arr[1],arr[2])
}1

$ awk -f tst.awk input.txt
0001 0044 0555 0001a 0044b 0565c 7890 77777
person Marc Lambrichs    schedule 27.09.2017
comment
ไม่แน่ใจว่าต้นบรรทัดจะมีตัวเลขเพียงตัวเดียวเนื่องจากผู้โพสต์ใช้แฟล็ก g สำหรับการแทนที่ - person xhienne; 28.09.2017
comment
อะไรทำให้สิ่งนี้ดีกว่าโซลูชัน sed ของ xhienne - person ghoti; 28.09.2017
comment
วิธีแก้ปัญหาของ xhienne ผิด มันจะเปลี่ยนหมายเลข 777777 เป็น 7777 - person Marc Lambrichs; 28.09.2017
comment
ผมขอใช้ถ้อยคำใหม่ โซลูชันของ Xhienne จัดการกับตัวเลขที่มีตัวเลขผิดมากกว่า 4 หลัก มีบางสิ่งที่ต้องระบุโดย OP ดังนั้นจึงไม่มีอะไรถูกหรือผิด - person Marc Lambrichs; 28.09.2017

นำหน้าแต่ละลำดับของตัวเลขด้วย 000 แล้วตัดทอนผลลัพธ์ให้เหลือสี่หลักสุดท้าย:

sed -i '
    s/[0-9]\{1,\}/000&/g
    s/0*\([0-9]\{4\}\)/\1/g
' "$FILE"

หรือด้วย GNU sed:

sed -i -r '
    s/[0-9]+/000&/g
    s/0*([0-9]{4})/\1/g
' "$FILE"

ตัวอย่าง:

Sample line : 1 44 555 1a 44b 565c 7890 77777

อัตราผลตอบแทน:

Sample line : 0001 0044 0555 0001a 0044b 0565c 7890 77777
person xhienne    schedule 28.09.2017
comment
ฉันขอแนะนำไม่ให้รวมตัวเลือก -i ที่นี่ แม้ว่าจะอยู่ในคำถามก็ตาม เนื่องจากการใช้งานนั้นแตกต่างกันระหว่างการใช้งาน sed โซลูชัน POSIX ที่แก้ไขไฟล์ต้นฉบับจะไม่สามารถทำได้ด้วย sed เพียงอย่างเดียว นอกจากนี้ เพื่อความเรียบง่าย อาจเป็นประโยชน์ที่จะกล่าวถึงว่าสามารถทำได้โดยไม่ต้องขึ้นบรรทัดใหม่ sed -e 's/[0-9]/000&/' -e 's/[0-9]*\([0-9]\{4\}\)/\1/g' เช่น แต่ถึงอย่างนั้น...ก็ทำได้ดีมาก :) - person ghoti; 28.09.2017
comment
วิธีนี้จะลดตัวเลขที่มากกว่า 4 หลักลง 7777777 จะถูกแปลงเป็น 7777 - person Marc Lambrichs; 28.09.2017
comment
@MarcLambrichs ใช่ - ไม่มีข้อมูลตัวอย่างของ OP ใดที่มีมากกว่า 4 หลัก พฤติกรรมในกรณีที่มีตัวเลข ›4 หลักไม่ได้ระบุไว้ในคำถาม - person ghoti; 28.09.2017
comment
@ghoti ขอบคุณ มีการขึ้นบรรทัดใหม่โดยเจตนาเพื่อให้สามารถอ่านได้ - person xhienne; 28.09.2017
comment
@ghoti ใช่ครับ เช่นเดียวกับที่ไม่ได้ระบุจำนวนคอลัมน์ในอินพุต - person Marc Lambrichs; 28.09.2017
comment
@MarcLambrichs อาจไม่มีตัวเลขเกิน 4 หลัก แต่คำตอบก็แก้ไขแล้ว ส่วนจำนวนคอลัมน์ ธงแทนที่ 'g' ระบุว่าอาจมีมากกว่าหนึ่งคอลัมน์ และไม่มีจุดยึดที่อาจระบุว่าตัวเลขอยู่ที่คอลัมน์แรก - person xhienne; 28.09.2017

หากต้องการจับคู่อักขระตั้งแต่ 0 ตัวขึ้นไป เราสามารถใช้ * และเพื่อจับคู่อักขระที่ไม่ใช่ตัวเลขใดๆ เราสามารถใช้ [^0-9]

ดังนั้น การปรับ regex ของคุณให้รวม [^0-9]* หลังตัวเลขตรงกันและก่อนรูปแบบที่ตรงกับส่วนที่เหลือของสตริงควรอนุญาตให้จับคู่ตัวอักษรเหล่านั้นได้

person Will Barnwell    schedule 27.09.2017

โปรดลองใช้ awk อีกวิธีหนึ่งแล้วแจ้งให้เราทราบหาก tis ช่วยคุณได้

awk '{val=$0;gsub(/[0-9]+/,"",val);printf("%04d%s\n",$0,val)}'  Input_file

ผลลัพธ์จะเป็นดังนี้

0001
0044
0555
0001a
0044b
0565c
7890

คำอธิบาย: เพิ่มรูปแบบการแก้ปัญหาแบบซับเดียวพร้อมคำอธิบายที่นี่ด้วย

awk '{
val=$0;                   ##Storing current line into a variable named val here.
gsub(/[0-9]+/,"",val);    ##Globally substituting all digits with NULL in variable val now, to make sure we are getting everything apart from digits.
printf("%04d%s\n",$0,val);##Now using printf of awk, whose quality is it will automatically take till all digits and do padding with zeros if needed till to make it 4 digit number that is why %04d is being used then I am using %s to print string with respect to the value of val, where we stored all values of strings previously.
}
' Input_file             ##Mentioning Input_file name here.
person RavinderSingh13    schedule 28.09.2017