Bagaimana cara mengekstrak / mem-parsing URL lengkap dari string semi acak?

12

Saya ingin mem-bash parse / mengekstrak URL lengkap (dan hanya url) dari string pendek acak.

Contoh:

bob, the address is http://www.google.com

atau

https://foo.com/category/example.html is up

atau

Error 123 occurred at http://bit.ly/~1223456677878

atau

Stats are up: https://foo1234.net/report.jpg

Saya mencoba menggunakan cat foo_output | egrep -o "https?://[\w'-\.]*\s"tetapi itu sepertinya tidak berhasil.

Mike B
sumber
Kedengarannya menakutkan, tergantung pada apa yang ingin Anda lakukan dengan URL yang diekstrak ...
vonbrand

Jawaban:

24

Apakah Anda sudah mencoba:

egrep -o 'https?://[^ ]+' foo_output

sebagai gantinya?

Perhatikan bahwa apa pun dengan kelas karakter dianggap literal, jadi mengatakan [\w]tidak cocok dengan karakter kata . Selain itu, Anda tidak perlu melarikan diri dari metacharacter regex dalam kelas karakter, yaitu, mengatakan [\.]tidak sama dengan [.].

devnull
sumber
2
[^ ]terlalu lebar, Anda akan ingin mengecualikan kosong lainnya, (, ), mungkin koma, dan semua karakter yang tidak diperbolehkan dalam URL.
Stéphane Chazelas
@StephaneChazelas Anda benar. Namun, saya berasumsi bahwa URL didahului dan diikuti oleh spasi kecuali di awal atau di akhir baris.
devnull
5

URI tidak cocok untuk pencocokan ekspresi reguler ketika tertanam dalam bahasa alami. Namun, keadaan saat ini adalah Improved Liberal, Accurate Regex Pattern dari John Gruber untuk URL yang Cocok . Seperti yang saat ini diposting, versi satu baris adalah sebagai berikut:

(?i)\b((?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))

John juga tampaknya mempertahankan intisari di sini , meskipun entri blog-nya melakukan pekerjaan yang jauh lebih baik untuk menjelaskan kumpulan tesnya dan keterbatasan pola ekspresi reguler.

Jika Anda ingin menerapkan ekspresi dari baris perintah, Anda mungkin menemukan diri Anda dibatasi oleh mesin ekspresi reguler yang Anda gunakan atau dengan masalah mengutip shell. Saya telah menemukan skrip Ruby sebagai opsi terbaik, tetapi jarak tempuh Anda mungkin beragam.

CodeGnome
sumber
2
Harap sertakan regex dalam jawaban Anda alih-alih menautkannya.
terdon
@terdon, regexp penuh adalah sekitar 60 baris.
vonbrand
2
@vonbrand saya tahu, saya melihatnya. Kami hanya cenderung menghindari tautan ke sumber daya eksternal. Inti dari situs SE adalah menjadi wiki. Bagaimana jika blog yang Anda tautkan menjadi offline? Jawaban Anda akan menjadi tidak berguna. Bagaimanapun, 60 baris tidak banyak dan hanya 60 baris untuk dibaca.
terdon
2

Masalah dengan URL yang cocok adalah bahwa apa saja bisa ada di URL:

https://encrypted.google.com/search?hl=en&q=foo#hl=en&q=foo&tbs=qdr:w,sbd:1

Seperti yang Anda lihat, (valid) URL di atas berisi $, ?, #, &, ,, .dan :. Pada dasarnya, satu-satunya hal yang Anda bisa pastikan URL tidak mengandung adalah ruang kosong. Dengan mengingat hal itu, Anda dapat mengekstrak URL Anda dengan pola sesederhana seperti:

$ grep -oP 'http.?://\S+' file 
http://www.google.com
https://foo.com/category/example.html
http://bit.ly/~1223456677878
https://foo1234.net/report.jpg

The \Scocok dengan non-ruang karakter dalam perl ekspresi reguler yang kompatibel (PCRE), yang -Pmengaktifkan PCRE untuk grepdan -omembuatnya mencetak hanya segmen cocok baris.

terdon
sumber
0

Saya akan pergi untuk merantai tetapi sedikit berbeda. Jika Anda memiliki cuplikan teks seperti milik Anda dalam file teks bernama strings.txt, Anda dapat melakukan hal berikut:

grep http ./strings.txt | sed 's/http/\nhttp/g' | grep ^http | sed 's/\(^http[^ <]*\)\(.*\)/\1/g' | grep IWANTthis | sort -u

Penjelasan:

grep http ./st3.txt      => will catch lines with http from text file
sed 's/http/\nhttp/g'    => will insert newline before each http
grep ^http               => will take only lines starting with http
sed 's/\(^http[^ <]*\)\(.*\)/\1/g'   
                         => will preserve string from ^http until first space or < (the latter in hope if 
grep IWANTthis           => will take only urls containing your text of your interest; you can omit this.
sort -u                  => will sort the list and remove duplicates from it 

Karena ada kemungkinan url tidak berfungsi, Anda dapat melakukan pengecekan kesalahan tambahan dengan URL yang Anda minati. misalnya wget -p URL -O /dev/null- itu akan mencetak kode kesalahan yang sangat berbeda seandainya URL tidak tersedia, sehingga Anda dapat mengatur lingkaran untuk memproses daftar tautan Anda dan menampilkan status validitasnya.

Jika Anda pada akhirnya mengekstraksi tautan dari file html maka mungkin ada beberapa masalah dengan sedkasus khusus. Seperti yang telah disarankan dalam lucu (posting) yang mungkin sudah Anda lihat - mungkin lebih baik tidak menggunakan regexps tetapi mesin parser html. Salah satu parser yang mudah tersedia adalah browser hanya teks lynx(tersedia di linux apa pun). Ini memungkinkan Anda untuk langsung membuang daftar semua tautan dalam sebuah file dan kemudian Anda cukup mengekstrak url yang Anda inginkan dengan grep.

lynx -dump -listonly myhtmlfile.html | grep IWANTthisString | sort -u

Namun ini tidak akan berfungsi pada sebagian besar file html yang rusak atau cuplikan teks dengan tautan.

r0berts
sumber
-1

Hanya egrep -o 'https?://[^ ")]+'

yang akan termasuk url()dan "http"

Roberto Bertó
sumber
3
Bagaimana ini berbeda dari jawaban oleh devnull? Saya harap Anda menyadari bahwa penggunaan egrepsudah usang.
Anthon
Jika Anda memiliki peningkatan atas jawaban yang ada, Anda dapat merujuk kembali melalui tautan "bagikan" di bawah jawaban itu. Lihat juga halaman bantuan
Jeff Schaller
-1
cat text-file.txt | grep -Eo '(https?|ftp|file)://[-A-Za-z0-9\+&@#/%?=~_|!:,.;]*[-A-Za-z0-9\+&@#/%=~_|]'

atau tambahkan perintah SED untuk menyimpannya ke file CSV:

| sed 's/;/<tab>/g' > file.csv
MakoBuk
sumber