Bagaimana cara 'menjatuhkan' / menghapus karakter dari depan string?

12

Saya memiliki string yang ingin saya manipulasi. String adalah H08W2345678bagaimana saya bisa memanipulasinya sehingga outputnya adil W2345678?

Demikian pula jika saya ingin H08W2345678mengeluarkan 4 karakter terakhir dari sehingga saya mendapatkan H08W234bagaimana saya melakukan ini?

3kstc
sumber
1
Ada banyak cara untuk memanipulasi string. Apakah ada alasan khusus untuk menggunakan sed?
don_crissti
@don_crissti Tidak ada alasan, terlepas dari kurangnya pengalaman. Alternatif apa pun dipersilakan ...
3kstc
@don_crissti, cerita: dari file CSV yang difilter, saya mengambil salah satu parameter dari baris yang ada H08W2345678dan perlu untuk memanipulasinya hingga W2345678Nilai ini dengan datum lain akan dimasukkan ke dalam email yang dikirim. Email Anda akan dilakukan dengan cron.
3kstc
@don_crissti awking itu. Saya membuat array dan kemudian memodifikasi setiap elemen dalam array (semuanya berbeda - yaitu mengubah timestaimp Epoch dalam hitungan detik menjadi tanggal dll.)
3kstc
2
Anda dapat melakukan hal-hal seperti itu dengan awk:printf %s\\n "XX,H08W2345678,YY" | awk -F, '{print substr($2, 4); print substr($2, 1, length($2)-4)}'
don_crissti

Jawaban:

18

Hanya menggunakan bash (atau dari ksh93mana sintaks itu berasal atau zsh):

string="H08W2345678"

echo "${string:3}"
W2345678

echo "${string:0:-4}"
H08W234

Lihat wiki Wooledge untuk informasi lebih lanjut tentang manipulasi string .

jasonwryan
sumber
Ini membutuhkan bash 4.2 atau lebih tinggi. Lihat salinan lama Manual Referensi Bash ini, Bagian 3.5.3, '' Ekspansi Parameter Shell '' atau jawaban anak ayam di sini untuk melihat batasan lama (“ panjang harus mengevaluasi ke angka yang lebih besar dari atau sama dengan nol.”); … (Lanjutan)
Scott
(Lanjutan) ... melihat perubahan Bash (di Bash Hacker Wiki) (gulir ke bawah ke bagian bawah bagian) atau berita pesta di Teknologi organisasi Infrastruktur Layanan di Case Western Reserve University (mencari “ditambahkan ke pesta-4.2” dan kemudian gulir ke bawah ke “q.”) untuk melihat revisi. ... ... ... ...  "${string:0:${#string}-4}" bekerja dalam versi bash 4.1 selama panjangnya $stringsetidaknya 4.
Scott
NB Ini juga akan tersedak string seperti abc-e, di mana, ketika Anda menjatuhkan tiga karakter pertama, Anda yang tersisa -e(karena echo -etidak melakukan apa yang Anda inginkan).
Scott
8
$ echo "H08W2345678" | sed 's/^.\{3\}//'
W2345678

sed 's/^.\{3\}//'akan menemukan tiga karakter pertama dengan ^.\{3\}dan mengganti dengan yang kosong. Di sini ^.akan cocok dengan karakter apa pun di awal string ( ^menunjukkan awal string) dan \{3\}akan cocok dengan pola sebelumnya tepat 3 kali. Jadi, ^.\{3\}akan cocok dengan tiga karakter pertama.

$ echo "H08W2345678" | sed 's/.\{4\}$//'
H08W234

Demikian pula, sed 's/.\{4\}$//'akan mengganti empat karakter terakhir dengan kosong ( $menunjukkan akhir dari string).

heemayl
sumber
1
Bisakah Anda jelaskan 's/^.\{3\}//'dan 's/.\{4\}$//'karena saya masih belajar sedikit, terima kasih banyak
3kstc
@ 3kstc: Silakan periksa hasil edit
heemayl
1
Untuk hanya beberapa karakter, saya akan menggunakan ...bukan .\{3\}karena (saya) lebih mudah untuk dibaca: sed -e 's/^...//' -e 's/....$//' atau dalam ekspresi tunggal dengan silih bergantinya: sed -r 's/^...|....$//g'. Jika lebih dari beberapa karakter untuk dihapus, maka saya akan menggunakan /.\{17}\/ekspresi bukan /.............../.
Johnny
Ini akan berperilaku buruk jika stringnya adalah -eatau -n. Tentu saja, arti dari “drop 4 karakter terakhir” tidak terdefinisi untuk string pendek dari 4 karakter, tetapi, jika seseorang ingin beradaptasi ini untuk menjatuhkan pertama atau terakhir satu karakter, itu bisa meledak.
Scott
2

Jika Anda memiliki file di mana setiap baris adalah string sebelas karakter (atau apa pun) yang ingin Anda potong, sedadalah alat untuk digunakan. Tidak apa-apa untuk memanipulasi string tunggal, tetapi itu berlebihan. Untuk string tunggal, jawaban Jason mungkin yang terbaik, jika Anda memiliki akses ke bash versi 4.2 atau lebih tinggi. Namun, dan sintaksis tampaknya unik untuk bash (well, bash, ksh93, mksh, dan zsh) - Saya tidak melihatnya di Spesifikasi Basis Grup Terbuka untuk Bahasa Perintah Shell . Jika Anda terjebak dengan shell yang mendukung POSIX yang tidak mendukung ekspansi substring (ekstraksi), Anda dapat menggunakan${parameter:offset}${parameter:offset:length}

$ printf "%s\n" "${string#???}"
W2345678

$ printf "%s\n" "${string%????}"
H08W234

menggunakan printfalih-alih echountuk menjaga terhadap string seperti abc-e, di mana, ketika Anda menjatuhkan tiga karakter pertama, Anda dibiarkan -e (dan echo -etidak melakukan apa yang Anda inginkan).

Dan, jika Anda tidak menggunakan shell Bourne-family sama sekali (atau Anda menggunakan sistem kuno, pra-POSIX), ini akan tetap berfungsi:

$ expr " $string" : ' ...\(.*\)'
W2345678

$ expr " $string" : ' \(.*\)....'
H08W234

Ruang terkemuka tambahan untuk menghindari masalah dengan nilai-nilai $string yang sebenarnya exproperator (misalnya, +,  /,  indexatau match) atau pilihan (misalnya,  --, --helpatau  --version).

Scott
sumber
@ Stéphane Chazelas: (1) Terima kasih telah mengingatkan saya pada jebakan yang saya tahu sekitar 40 tahun yang lalu dan entah bagaimana berhasil melupakan. (2) Saya selalu menyelesaikan ini dengan X; misalnya expr "X$string" : 'X...\(.*\)',. IMO, itu lebih mudah dibaca dan dimengerti. Apakah ada masalah dengan itu, atau ada alasan untuk memilih ruang? (3) Hari ini saya belajar bahwa expr + "$string" : '...\(.*\)'sekarang berhasil. Saya tidak ingat itu dari 40 tahun yang lalu; apakah cukup banyak digunakan agar aman untuk direkomendasikan? (4) Anda melewatkan sebuah catatan tentang jawaban jasonwryan dan sebuah pilihan pada jawaban heemayl.
Scott
AFAIK, itu expr +hanya GNU (tidak akan berfungsi pada Solaris atau FreeBSD AFAICS). Saya menggunakan ruang alih-alih x karena lebih kecil kemungkinannya bahwa beberapa exprimplementasi akan memiliki operator yang memulai dengan ruang daripada dengan xdan juga karena lebih kecil kemungkinannya ada elemen penyatuan yang dimulai dengan ruang daripada dengan x. Tapi kemudian saya menyadari itu mungkin bukan pilihan yang baik expr " $a" "<" " $b"untuk perbandingan string karena beberapa implementasi akhirnya melakukan perbandingan numerik ketika $a/ $bterlihat seperti angka. Mungkin expr "@@$a"...atau expr "x $a"bisa lebih aman.
Stéphane Chazelas
0

Dengan:

string="H08W2345678"

Mencocokkan 3 atau 4 karakter tampaknya sederhana (untuk sebagian besar shell):

$ printf '%s\t%s\n' "${string#???}" "${string%????}"
W2345678      H08W234

Untuk cangkang yang lebih lama (seperti cangkang Bourne), gunakan:

$ string=H08W2345678

$ expr " ${string}" : " ...\(.*\)"
W2345678

$ expr " ${string}" : " \(.*\)...." '
H08W234

Jika diperlukan jumlah karakter, gunakan:

$ expr " ${string}" : " .\{3\}\(.*\)"
W2345678

$ expr " ${string}" : " \(.*\).\{4\}" '
H08W234

Tentu saja, regex tersebut juga berfungsi dengan sed, awk, dan bash 3.0+:

$ echo "$string" | sed 's/^.\{3\}//'
W2345678

$ echo "$string" | sed 's/.\{4\}$//'
H08W234

$ echo "$string" | awk '{sub(/^.{3}/,"")}1'
W2345678

$ echo "$string" | awk '{sub(/.{4}$/,"")}1'
H08W234

$ r='^.{3}(.*)$'; [[ $a =~ $r ]] && echo "${BASH_REMATCH[1]}"
W2345678

$ r='^(.*).{4}$'; [[ $a =~ $r ]] && echo "${BASH_REMATCH[1]}"
H08W234
NotAnUnixNazi
sumber
-1

Bagaimana cara 'menjatuhkan' / menghapus karakter dari depan string?

Saya memiliki string yang ingin saya manipulasi. String adalah H08W2345678 bagaimana saya bisa memanipulasinya sehingga outputnya hanya W2345678?

echo "H08W2345678" | cut -c 4-
aexl
sumber
Ini hanya menjawab setengah dari pertanyaan.
Kusalananda
Saya yakin downvote Anda tidak adil. Setengah ini menjawab pertanyaan yang saya miliki ketika saya googled posix menghapus karakter pertama dan halaman ini muncul di hasil pencarian. Selain itu, judul halaman ini hanya mencakup setengah dari pertanyaan itu. Saya kembali dan berkontribusi ketika saya menemukan solusi yang saya sukai - saya pikir untuk pekerjaan cutitu jauh lebih elegan daripada apa pun yang ada di halaman ini.
aexl