Saya mencari cara untuk mengganti string placeholder dalam file template dengan nilai konkret, dengan alat Unix umum (bash, sed, awk, mungkin perl). Penting bahwa penggantian dilakukan dalam sekali jalan, yaitu, apa yang sudah dipindai / diganti tidak harus dipertimbangkan untuk penggantian lain. Misalnya, kedua upaya ini gagal:
echo "AB" | awk '{gsub("A","B");gsub("B","A");print}'
>> AA
echo "AB" | sed 's/A/B/g;s/B/A/g'
>> AA
Hasil yang benar dalam kasus ini tentu saja adalah BA.
Secara umum, solusinya harus sama dengan memindai input kiri-ke-kanan untuk kecocokan terpanjang ke salah satu string pengganti yang diberikan, dan untuk setiap kecocokan, melakukan penggantian dan melanjutkan dari titik itu pada input (tidak ada sudah membaca input atau penggantian yang dilakukan harus dipertimbangkan untuk pertandingan). Sebenarnya, detailnya tidak masalah, hanya saja hasil penggantian tidak pernah dipertimbangkan untuk penggantian lain, seluruhnya atau sebagian.
CATATAN Saya hanya mencari solusi generik yang benar. Tolong jangan mengusulkan solusi yang gagal untuk input tertentu (input file, cari dan ganti pasangan), namun tampaknya tidak mungkin.
tr AB BA
.Jawaban:
OK, solusi umum. Fungsi bash berikut membutuhkan
2k
argumen; masing-masing pasangan terdiri dari pengganti dan satu pengganti. Terserah Anda untuk mengutip string dengan tepat untuk meneruskannya ke dalam fungsi. Jika jumlah argumen aneh, argumen kosong implisit akan ditambahkan, yang secara efektif akan menghapus kejadian placeholder terakhir.Baik penampung atau pengganti tidak boleh mengandung karakter NUL, tetapi Anda dapat menggunakan standar C
\
-escapes seperti\0
jika Anda membutuhkanNUL
(dan akibatnya Anda harus menulis\\
jika Anda menginginkan a\
).Ini membutuhkan alat bantu standar yang harus ada pada sistem seperti posix (lex dan cc).
Kami berasumsi bahwa
\
sudah lolos jika perlu dalam argumen tetapi kami harus lolos dari tanda kutip ganda, jika ada. Itulah yang dilakukan argumen kedua ke printf kedua. Karenalex
tindakan defaultnya adalahECHO
, kita tidak perlu khawatir tentang hal itu.Contoh menjalankan (dengan timing untuk skeptis; itu hanya laptop komoditas murah):
Untuk input yang lebih besar, mungkin berguna untuk menyediakan flag optimasi
cc
, dan untuk kompatibilitas Posix saat ini, akan lebih baik untuk digunakanc99
. Implementasi yang bahkan lebih ambisius mungkin mencoba untuk membuat cache executable yang dihasilkan alih-alih menghasilkan mereka setiap kali, tetapi mereka tidak benar-benar mahal untuk dihasilkan.Edit
Jika Anda memiliki tcc , Anda dapat menghindari kerumitan membuat direktori sementara, dan menikmati waktu kompilasi yang lebih cepat yang akan membantu pada input berukuran normal:
sumber
fn() { tcc ; } <<CODE\n$(gen code)\nCODE\n
. Bisakah saya bertanya - ini jawaban yang luar biasa dan saya memutarnya segera setelah saya membacanya - tapi saya tidak mengerti apa yang terjadi pada susunan shell? Apa fungsinya"${@//\"/\\\"}"
?Sesuatu seperti ini akan selalu mengganti setiap kemunculan string target Anda hanya sekali saat mereka terjadi
sed
dalam aliran dengan satu gigitan per baris. Ini adalah cara tercepat yang dapat saya bayangkan Anda akan melakukannya. Kemudian lagi, saya tidak menulis C. Tapi ini benar-benar menangani pembatas nol jika Anda menginginkannya. Lihat jawaban ini untuk cara kerjanya. Ini tidak memiliki masalah dengan karakter shell khusus yang terkandung atau serupa - tetapi itu adalah ASCII spesifik lokal, atau, dengan kata lain,od
tidak akan menampilkan karakter multi-byte pada baris yang sama dan hanya akan melakukan satu per. Jika ini masalah, Anda ingin menambahkaniconv
.sumber
sed
dan menyimpan hingga nol atau sesuatu lalu minta yangsed
menulis skrip ini; atau letakkan di fungsi shell dan berikan nilai pada satu gigitan per baris seperti"/$1/"
..."/$2/"
- mungkin saya akan menulis fungsi-fungsi itu juga ...PLACE1
,PLACE2
danPLA
.PLA
selalu menang. OP mengatakan: "setara dengan memindai input kiri-ke-kanan untuk pertandingan terlama dengan salah satu string pengganti yang diberikan" (penekanan ditambahkan)Sebuah
perl
solusi. Bahkan jika beberapa menyatakan itu tidak mungkin, saya menemukan satu tetapi secara umum pertandingan sederhana dan ganti tidak mungkin dan bahkan semakin buruk karena pengulangan NFA hasilnya bisa tidak terduga.Secara umum, dan ini harus dikatakan, masalahnya menghasilkan hasil yang berbeda yang tergantung pada urutan dan panjang tupel pengganti. yaitu:
dan input
AAA
menghasilkanBBB
atauCCB
.Berikut kodenya:
Checkerbunny:
sumber