Bagaimana Anda menyimpan regex kompleks untuk digunakan kembali dalam jumlah banyak?


12

Dalam menggunakan sed, saya sering membuat regex yang agak rumit dan rumit yang harus saya cocokkan dua kali dalam file. Apakah ada cara bagi saya untuk menyimpan regex ini dan hanya referensi dua kali?

Mungkin sesuatu yang terlihat seperti ini?

sed ' complicated_regex=/^(([a-f0-9]{32})+([a-zA-Z0-9=]{{$i}})?)+$/
s/complicated_regex:complicated_regex/simple-output/
' my_file

Pembaruan: Sebuah jawaban telah menyajikan solusi menggunakan variabel bash. Ini tidak berhasil. Diberikan a test.txt.

#test.txt
foo bar
bar foo

Dan skripnya

#!/bin/bash

VALUE='foo \([a-z]\+\)'

sed 's/"${VALUE}"/foo happy \1/' test.txt

Ini harus menghasilkan output

foo happy bar
bar foo

Tapi saya malah mendapatkan kesalahan

sed: -e expression #1, char 24: invalid reference \1 on `s' command's RHS

Jika Anda menggunakan Perl, Anda dapat mereferensikan bagian-bagian sebelumnya dari ekspresi dalam ekspresi:perl -pe 's/^(([a-f0-9]{32})+([a-zA-Z0-9=]{{$i}})?)+:\1$/simple_output/' my_file
glenn jackman

1
Ketika Anda menemukan sesuatu yang terlalu rumit untuk sed, jangan ragu untuk mencari awk atau perl.
Gilles 'SO- stop being evil'

2
@Cory: Contoh Anda berfungsi dengan baik, jika Anda mendapatkan sintaksnya dengan benar. Anda memiliki "variabel $" masih terlampir dalam 'tanda kutip tunggal' yang menyembunyikannya dari ekspansi shell yang Anda harapkan ... seharusnyased 's/'"${VALUE}"'/foo happy \1/' test.txt
Peter.O

Jawaban:


7

Anda dapat menggunakan variabel shell:

complicated_regex='(([a-f0-9]{32})+([a-zA-Z0-9=]{{$i}})?)+'
sed s/^"$complicated_regex":"$complicated_regex"\$/'simple-output'/ my_file

Saya tidak yakin tentang apa yang Anda maksudkan $i, tetapi Anda mungkin harus meletakkannya di luar tanda kutip tunggal:

complicated_regex='(([a-f0-9]{32})+([a-zA-Z0-9=]{{'"$i"'}})?)+'

Tentu saja ini hanya berfungsi jika sedperintah dijalankan dari shell, tetapi ada solusi serupa dengan hampir semua bahasa pemrograman. (Dan saya rasa tidak mungkin menggunakan variabel di dalamnya sed.)
Stéphane Gimenez

Hrm Mencoba ini, referensi-ulang tampaknya rusak. s/$complicated_regex/\1/memberikan kesalahan yang mengatakan bahwa itu adalah referensi yang tidak valid.
Cory Klein

Ah, mungkin salahku, aku sudah terbiasa dengan penggantian variabel zsh. Lihat jawaban yang diperbarui.
Stéphane Gimenez

Anda harus menghapus jangkar dari variabel dan meletakkannya di skrip sed:sed "s/^${complicated_regex}:${complicated_regex}\$/simple-output/" my_file
glenn jackman

Duh! Ya, saya lupa memeriksa bahwa saya diberikan gabungan regex yang valid :-)
Stéphane Gimenez

0

Cara termudah untuk memasukkan nilai variabel shell ke seddan tidak khawatir tentang bagaimana backslash-escaping Anda perlu diubah untuk sisa sedskrip Anda , adalah dengan memasukkan semuanya ke dalam tanda kutip tunggal kecuali variabel, dan memasukkannya ke dalam tanda kutip ganda.

Semua contoh kode berikut menganggap: VALUE='foo \([a-z]\+\)'

Kode rusak berikut gagal karena variabel VALUEtidak diperluas:

sed 's/"${VALUE}"/foo happy \1/' test.txt

Kode rusak berikut gagal karena garis miring terbalik \1dimakan oleh shell (karena itu dalam tanda kutip ganda daripada tanda kutip tunggal) sebelum sedpernah melihatnya:

sed "s/${VALUE}/foo happy \1/" test.txt

Kode berikut berfungsi seperti yang diharapkan:

sed 's/'"${VALUE}"'/foo happy \1/' test.txt

Kode berikut juga berfungsi:

sed "s/${VALUE}/foo happy \\1/" test.txt

Begitu juga yang berikut:

sed s/"${VALUE}"/foo\ happy\ \\1/ test.txt

Tetapi mengapa menjadi rumit? Kutipan tunggal di sekitar sedskrip membuat semuanya lebih jelas, terutama bagi guru yang tidak memiliki skrip-scripting yang membaca kode Anda. Cara favorit saya adalah, sekali lagi, keluar dari tanda kutip tunggal menjadi tanda kutip ganda hanya untuk ekspansi variabel dan langsung kembali ke tanda kutip tunggal:

sed 's/'"${VALUE}"'/foo happy \1/' test.txt
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.