Abaikan kemungkinan non-digit di akhir angka dalam substitusi sed

Saya perlu mengisi string dengan nol hingga mencapai batas empat digit, misalnya:

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

Saya memiliki skrip bash dan saya menambahkan file yang berisi angka-angka itu sebagai parameter.

#!/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

Skrip tidak berfungsi pada 1a, 44b, 565c. Saya tidak tahu bagaimana mengabaikan surat-surat itu.


person Mr. Kevin    schedule 27.09.2017    source sumber
comment
\> cocok dengan batas kata: 1a dianggap satu kata   -  person Andrea Corbellini    schedule 28.09.2017
comment
Kemungkinan duplikat dari Mengisi angka nol dalam string   -  person funky-future    schedule 28.09.2017
comment
Saya tidak setuju dengan dupe flag @funky-future, pertanyaan itu tentang penggunaan printf, ini tentang sed, dalam kedua kasus, penanya sudah tahu cara melakukan padding dan mengalami masalah dengan implementasi   -  person Will Barnwell    schedule 28.09.2017
comment
Bisakah Anda memberikan jalur masukan yang khas? Bisakah ada beberapa nomor seperti itu per baris?   -  person xhienne    schedule 28.09.2017
comment
Selamat datang di Stack Overflow! Mohon jangan merusak postingan Anda. Dengan memposting di jaringan Stack Exchange, Anda telah memberikan hak yang tidak dapat dibatalkan kepada SE untuk mendistribusikan konten tersebut (di bawah lisensi CC BY-SA 3.0). Dengan kebijakan SE, segala vandalisme akan dibatalkan. Jika Anda ingin memisahkan postingan ini dari akun Anda, lihat Apa rute yang tepat untuk permintaan pemisahan?   -  person Suraj Rao    schedule 28.09.2017


Jawaban (4)


GNU awk akan menjadi alat yang lebih baik di sini:

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

yang berisi $1 hingga 4 digit.

Pengujian:

$ 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

Misalkan data diurutkan seperti pada jawaban @xhienne, lalu kita mengulang bidang:

$ 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
Tidak yakin hanya ada satu nomor di awal baris karena poster menggunakan bendera g sebagai penggantinya. - person xhienne; 28.09.2017
comment
Apa yang membuat ini lebih baik daripada solusi sed xhienne? - person ghoti; 28.09.2017
comment
solusi xhienne salah. Ini akan mengubah angka 777777 menjadi 7777. - person Marc Lambrichs; 28.09.2017
comment
Biarkan saya ulangi. Solusi Xhienne menangani angka yang salah lebih dari 4 digit. Ada beberapa hal yang perlu ditentukan oleh OP, oleh karena itu tidak ada benar atau salah. - person Marc Lambrichs; 28.09.2017

Awali setiap urutan digit dengan 000 lalu potong hasilnya menjadi empat digit terakhir:

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

Atau dengan GNU sed:

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

Contoh:

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

Hasil:

Sample line : 0001 0044 0555 0001a 0044b 0565c 7890 77777
person xhienne    schedule 28.09.2017
comment
Saya menyarankan untuk tidak menyertakan opsi -i di sini, meskipun faktanya opsi tersebut ada dalam pertanyaan, karena penggunaannya berbeda antara implementasi sed. Solusi POSIX yang memodifikasi file asli tidak akan mungkin dilakukan hanya dengan sed. Selain itu, demi kesederhanaan, mungkin berguna untuk menyebutkan bahwa ini dapat dilakukan tanpa baris baru. sed -e 's/[0-9]/000&/' -e 's/[0-9]*\([0-9]\{4\}\)/\1/g' misalnya. Tapi meskipun begitu... bagus sekali. :) - person ghoti; 28.09.2017
comment
Ini akan mengurangi angka yang lebih dari 4 digit. 7777777 akan diubah menjadi 7777. - person Marc Lambrichs; 28.09.2017
comment
@MarcLambrichs, ya -- tidak ada data sampel OP yang lebih dari 4 digit. Perilaku dalam kasus dengan ›4 digit tidak ditentukan dalam pertanyaan. - person ghoti; 28.09.2017
comment
@ghoti Terima kasih. Baris baru sengaja ditambahkan demi keterbacaan. - person xhienne; 28.09.2017
comment
@ghoti Yup. Sama seperti jumlah kolom pada input yang tidak ditentukan. - person Marc Lambrichs; 28.09.2017
comment
@MarcLambrichs Mungkin tidak ada angka yang melebihi 4 digit, tapi jawabannya tetap diperbaiki. Sedangkan untuk jumlah kolom, tanda substitusi 'g' menunjukkan mungkin ada lebih dari satu, dan tidak ada jangkar yang mungkin menunjukkan bahwa nomor tersebut ada di kolom pertama. - person xhienne; 28.09.2017

Untuk mencocokkan nol atau lebih karakter kita dapat menggunakan * dan untuk mencocokkan non-digit apa pun kita dapat menggunakan [^0-9]

Jadi mengadaptasi regex Anda untuk memasukkan [^0-9]* setelah digit cocok dan sebelum pola cocok dengan sisa string akan memungkinkan pencocokan huruf-huruf tersebut.

person Will Barnwell    schedule 27.09.2017

Bisakah Anda mencoba satu pendekatan lagi dengan awk dan beri tahu saya jika ini membantu Anda.

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

Outputnya adalah sebagai berikut.

0001
0044
0555
0001a
0044b
0565c
7890

Penjelasan: Menambahkan bentuk solusi non-satu liner dengan penjelasan juga di sini.

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