Saya mencoba menggunakan sed untuk membersihkan baris URL untuk mengekstrak domain saja.
Jadi dari:
http://www.suepearson.co.uk/product/174/71/3816/
Saya ingin:
http://www.suepearson.co.uk/
(baik dengan atau tanpa garis miring, tidak masalah)
Saya telah mencoba:
sed 's|\(http:\/\/.*?\/\).*|\1|'
dan (menghindari quantifier yang tidak rakus)
sed 's|\(http:\/\/.*\?\/\).*|\1|'
tapi sepertinya saya tidak bisa mendapatkan quantifier non-serakah ( ?
) untuk bekerja, jadi selalu cocok dengan seluruh string.
sed -E 's...
. Tetap saja, tidak ada operator yang enggan.cut -d'/' -f1-3
karya sederhana .Jawaban:
Regex Posix / GNU dasar atau diperluas tidak mengakui quantifier yang tidak rakus; Anda perlu regex nanti. Untungnya, Perl regex untuk konteks ini cukup mudah didapat:
sumber
-pi -e
.perl
yang diperlukan oleh POSIXsed
, menggunakan sintaksis yang pada dasarnya identik dengansed
Dalam kasus khusus ini, Anda bisa menyelesaikan pekerjaan tanpa menggunakan regex yang tidak serakah.
Coba regex non-serakah ini
[^/]*
alih-alih.*?
:sumber
([^&=#]+)=([^&#]*)
. Ada kasus-kasus yang tidak bekerja dengan cara ini pasti, misalnya ketika mem-parsing URL untuk bagian inang dan pathname-nya dengan slash akhir dianggap opsional untuk dikecualikan dari penangkapan:^(http:\/\/.+?)/?$
Dengan sed, saya biasanya menerapkan pencarian non-serakah dengan mencari apa pun kecuali pemisah sampai pemisah:
Keluaran:
ini adalah:
-n
s/<pattern>/<replace>/p
;
pemisah perintah pencarian alih-alih/
untuk membuatnya lebih mudah untuk mengetiknyas;<pattern>;<replace>;p
\(
...\)
, nanti dapat diakses dengan\1
,\2
...http://
[]
,[ab/]
berarti baika
ataub
atau/
^
di[]
berartinot
, sehingga diikuti oleh apa pun kecuali hal di[]
[^/]
artinya apa pun kecuali/
karakter*
adalah mengulangi grup sebelumnya sehingga[^/]*
berarti karakter kecuali/
.sed -n 's;\(http://[^/]*\)
berarti mencari dan mengingathttp://
diikuti oleh setiap karakter kecuali/
dan ingat apa yang Anda temukan/
jadi tambah yang lain/
di akhir:sed -n 's;\(http://[^/]*\)/'
tetapi kami ingin mencocokkan sisa baris setelah domain jadi tambahkan.*
\1
) adalah domain, jadi ganti baris yang cocok dengan barang yang disimpan dalam grup\1
dan cetak:sed -n 's;\(http://[^/]*\)/.*;\1;p'
Jika Anda juga ingin menyertakan backslash setelah domain, tambahkan satu backslash lagi di grup untuk diingat:
keluaran:
sumber
sed tidak mendukung operator "tidak rakus".
Anda harus menggunakan operator "[]" untuk mengecualikan "/" dari kecocokan.
PS tidak perlu backslash "/".
sumber
s/([[:digit:]]\.[[1-9]]*)0*/\1/
jelas tidak akan bekerja dengan baik1.20300
. Karena pertanyaan aslinya adalah tentang URL, maka harus disebutkan dalam jawaban yang diterima.Simulasi quantifier lazy (un-greedy) di
sed
Dan semua rasa regex lainnya!
Menemukan kemunculan pertama ekspresi:
POSIX ERE (menggunakan
-r
opsi)Regex:
Sed:
Contoh (menemukan urutan angka pertama) Demo langsung :
Bagaimana cara kerjanya ?
Regex ini mendapat manfaat dari pergantian
|
. Pada setiap posisi mesin mencoba untuk memilih pertandingan yang paling lama (ini adalah standar POSIX yang diikuti oleh beberapa mesin lain juga) yang artinya berjalan.
sampai pertandingan ditemukan([0-9]+).*
. Tetapi ketertiban juga penting.Karena flag global disetel, engine mencoba untuk melanjutkan pencocokan karakter demi karakter hingga akhir string input atau target kami. Segera setelah kelompok pertama dan satu-satunya menangkap sisi kiri pergantian dicocokkan
(EXPRESSION)
sisa baris dikonsumsi segera juga.*
. Kami sekarang memegang nilai kami di grup penangkapan pertama.POSIX BRE
Regex:
Sed:
Contoh (menemukan urutan angka pertama):
Yang ini seperti versi ERE tetapi tanpa pergantian. Itu saja. Pada setiap posisi mesin mencoba untuk mencocokkan angka.
Jika ditemukan, digit berikut lainnya dikonsumsi dan ditangkap dan sisa garis dicocokkan segera jika tidak karena
*
berarti lebih atau nol melompati kelompok penangkap kedua\(\([0-9]\{1,\}\).*\)*
dan tiba pada titik.
untuk mencocokkan satu karakter dan proses ini berlanjut.Menemukan kemunculan pertama ekspresi terbatas :
Pendekatan ini akan cocok dengan kemunculan pertama string yang dibatasi. Kita bisa menyebutnya blok string.
String input:
-EDE:
end
-SDE:
start
Keluaran:
Regex pertama
\(end\).*
cocok dan menangkap pembatas ujung pertamaend
dan mengganti semua cocok dengan karakter yang diambil terakhir yang merupakan pembatas akhir. Pada tahap ini output kami adalah:foobar start block #1 end
.Kemudian hasilnya diteruskan ke regex kedua
\(\(start.*\)*.\)*
yang sama dengan versi POSIX BRE di atas. Ini cocok dengan satu karakter jika pembatas mulaistart
tidak cocok jika tidak cocok dan menangkap pembatas mulai dan cocok dengan sisa karakter.Langsung menjawab pertanyaan Anda
Dengan menggunakan pendekatan # 2 (ekspresi terbatas) Anda harus memilih dua ekspresi yang sesuai:
EDE:
[^:/]\/
SDE:
http:
Pemakaian:
Keluaran:
Catatan: ini tidak akan bekerja dengan pembatas identik.
sumber
sed
dan semua mesin lainnya mengikuti urutan standar yang sama tidak masalah ketika datang ke kesetaraan. Jadiecho 'foo 1' | sed -r 's/.|([0-9]+).*/\1/g'
tidak ada yang cocok tetapiecho 'foo 1' | sed -r 's/([0-9]+).*|./\1/g'
tidak.Solusi non-serakah untuk lebih dari satu karakter
Utas ini benar-benar tua tetapi saya menganggap orang masih membutuhkannya. Katakanlah Anda ingin membunuh segalanya sampai kejadian pertama
HELLO
. Anda tidak bisa mengatakan[^HELLO]
...Jadi solusi yang bagus melibatkan dua langkah, dengan asumsi bahwa Anda dapat menyimpan kata unik yang tidak Anda harapkan dalam input, katakan
top_sekrit
.Dalam hal ini kita dapat:
Tentu saja, dengan input yang lebih sederhana Anda dapat menggunakan kata yang lebih kecil, atau bahkan mungkin satu karakter.
HTH!
sumber
`
, saya akan menggunakan<$$>
(karena$$
memperluas ke ID proses Anda di shell, meskipun Anda harus menggunakan tanda kutip ganda daripada tanda kutip tunggal, dan itu mungkin merusak bagian lain dari regex Anda) atau, jika unicode tersedia, sesuatu seperti<∈∋>
.perl
ataupython
atau bahasa lain saja.perl
melakukan ini dengan cara yang kurang rapuh dalam satu baris ...pencocokan sed - non serakah oleh Christoph Sieghart
Trik untuk mendapatkan pencocokan tidak serakah di sed adalah untuk mencocokkan semua karakter tidak termasuk yang mengakhiri pertandingan. Saya tahu, seorang yang tidak punya otak, tetapi saya menghabiskan menit-menit berharga untuk itu dan skrip shell seharusnya, cepat dan mudah. Jadi kalau-kalau ada orang lain yang membutuhkannya:
Pencocokan serakah
Pencocokan non serakah
sumber
Ini dapat dilakukan dengan menggunakan cut:
sumber
cara lain, tidak menggunakan regex, adalah dengan menggunakan bidang / metode pembatas mis
sumber
sed
tentu memiliki tempat tetapi ini bukan salah satu dari mereka!Seperti yang ditunjukkan Dee: Gunakan saja
cut
. Jauh lebih sederhana dan jauh lebih aman dalam hal ini. Berikut ini contoh di mana kami mengekstrak berbagai komponen dari URL menggunakan sintaks Bash:Memberi anda:
Seperti yang Anda lihat, ini adalah pendekatan yang jauh lebih fleksibel.
(semua kredit ke Dee)
sumber
sumber
sed -E mengartikan ekspresi reguler sebagai ekspresi reguler extended (modern)
Pembaruan: -E pada MacOS X, -r di GNU sed.
sumber
-E
ini unik untuk BSDsed
dan karenanya OS X. Tautan ke halaman manual.-r
tidak membawa ekspresi reguler yang diperluas ke GNUsed
seperti yang tercantum dalam koreksi @ stephancheg. Hati-hati saat menggunakan perintah variabilitas yang dikenal di seluruh distribusi nix. Saya mempelajarinya secara susah-payah.-r
Opsi GNU sed hanya mengubah aturan pelolosan, sesuai denganAppendix A Extended regular expressions
file info dan beberapa tes cepat; itu sebenarnya tidak menambahkan kualifikasi non-serakah (GNU sed version 4.2.1
setidaknya sampai).-E
sebagai opsi tidak berdokumen untuk sementara waktu, tetapi dalam rilis 4.2.2.177 , dokumentasi telah diperbarui untuk mencerminkan hal itu, jadi-E
tidak masalah untuk keduanya sekarang.Masih ada harapan untuk menyelesaikan ini dengan menggunakan pure (GNU) sed. Meskipun ini bukan solusi umum dalam beberapa kasus, Anda dapat menggunakan "loop" untuk menghilangkan semua bagian string yang tidak perlu seperti ini:
Satu-satunya masalah di sini adalah ia juga akan memotong karakter pemisah terakhir ('/'), tetapi jika Anda benar-benar membutuhkannya Anda masih dapat dengan mudah memasukkannya kembali setelah "loop" selesai, tambahkan saja perintah tambahan ini di akhir sebelumnya garis komando:
sumber
Karena Anda secara khusus menyatakan sedang mencoba menggunakan sed (alih-alih perl, memotong, dll.), Cobalah mengelompokkan. Ini menghindari pengidentifikasi non-serakah yang berpotensi tidak dikenali. Grup pertama adalah protokol (yaitu 'http: //', 'https: //', 'tcp: //', dll). Grup kedua adalah domain:
Jika Anda tidak terbiasa dengan pengelompokan, mulailah dari sini .
sumber
Saya menyadari ini adalah entri lama, tetapi seseorang mungkin menganggapnya berguna. Karena nama domain lengkap tidak boleh melebihi total panjang 253 karakter ganti. * Dengan. \ {1, 255 \}
sumber
Ini adalah cara melakukan pencocokan non-serakah dari string multi-karakter menggunakan sed. Katakanlah Anda ingin mengubah setiap
foo...bar
untuk<foo...bar>
jadi misalnya masukan ini:harus menjadi output ini:
Untuk melakukan itu, Anda mengonversi foo dan bilah menjadi karakter individual dan kemudian menggunakan negasi dari karakter tersebut di antara mereka:
Di atas:
s/@/@A/g; s/{/@B/g; s/}/@C/g
mengonversi{
dan}
ke string placeholder yang tidak dapat ada di input sehingga karakter-karakter tersebut kemudian tersedia untuk dikonversifoo
danbar
ke.s/foo/{/g; s/bar/}/g
mengkonversifoo
danbar
ke{
dan}
masing - masings/{[^{}]*}/<&>/g
sedang melakukan operasi yang kita inginkan - mengonversifoo...bar
ke<foo...bar>
s/}/bar/g; s/{/foo/g
mengubah{
dan}
kembali kefoo
danbar
.s/@C/}/g; s/@B/{/g; s/@A/@/g
sedang mengonversi string placeholder kembali ke karakter aslinya.Perhatikan bahwa hal di atas tidak bergantung pada string tertentu yang tidak ada pada input karena string tersebut diproduksi pada langkah pertama, juga tidak peduli kemunculan regexp tertentu yang ingin Anda cocokkan karena Anda dapat menggunakan
{[^{}]*}
sebanyak yang diperlukan dalam ekspresi untuk mengisolasi kecocokan sebenarnya yang Anda inginkan dan / atau dengan operator pencocokan angka sed, misalnya untuk hanya mengganti kemunculan ke-2:sumber
Belum melihat jawaban ini, jadi inilah cara Anda dapat melakukan ini dengan
vi
atauvim
:Ini menjalankan
vi
:%s
substitusi secara global (trailingg
), menahan diri untuk tidak meningkatkan kesalahan jika pola tidak ditemukan (e
), kemudian menyimpan perubahan yang dihasilkan ke disk dan berhenti. The&>/dev/null
mencegah GUI dari singkat berkedip pada layar, yang dapat mengganggu.Saya suka menggunakan
vi
kadang-kadang untuk regex super rumit, karena (1) perlmatisekarat, (2) vim memiliki mesin regex yang sangat canggih, dan (3) Saya sudah akrab dengan regex dalamvi
pengeditan penggunaan sehari-hari saya dokumen.sumber
jangan repot-repot, saya mendapatkannya di forum lain :)
sumber
/home/one/two/three/
, jika Anda menambahkan lain/
seperti/home/one/two/three/four/myfile.txt
Anda rakus akan cocokfour
juga:/home/one/two/three/four
, pertanyaannya adalah tentang non-serakahsed 's|\(http:\/\/www\.[a-z.0-9]*\/\).*|\1|
bekerja jugasumber
Ini adalah sesuatu yang dapat Anda lakukan dengan pendekatan dua langkah dan awk:
Semoga itu bisa membantu!
sumber
Versi sed lainnya:
Ini cocok
/
diikuti oleh karakter alfanumerik (jadi bukan slash maju lain) serta sisa karakter hingga akhir baris. Setelah itu menggantinya dengan apa-apa (mis. Menghapusnya.)sumber
"[[:alnum:]]"
, bukan"[:alphanum:]"
.