Как я могу извлечь / разобрать полный URL из полу случайной строки?

12

Я хотел бы, чтобы bash анализировал / извлекал полный URL (и только URL) из случайной короткой строки.

Примеры:

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

или

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

или

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

или

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

Я пытался использовать, cat foo_output | egrep -o "https?://[\w'-\.]*\s"но это не сработало.

Майк Б
источник
Звучит страшно, в зависимости от того, что вы хотите сделать с извлеченным URL ...
vonbrand

Ответы:

24

Ты пробовал:

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

вместо?

Обратите внимание, что все, что связано с классом символов, воспринимается как литерал, поэтому выражение [\w]не соответствует символу слова . Более того, вам не нужно избегать метасимволов регулярных выражений в классе символов, т. Е. Говорить [\.]не совсем то же самое, что и [.].

devnull
источник
2
[^ ]слишком широк, вы хотите , чтобы исключить другие пробелы, (, ), возможно , запятые, и все символы, которые не разрешены в URL.
Стефан Шазелас,
@ StephaneChazelas Ты прав. Тем не менее, я предположил, что URL предшествует и сопровождается пробелом, если только в начале или конце строки.
devnull
5

URI не подходят для сопоставления регулярных выражений, когда они встроены в естественный язык. Тем не менее, текущее состояние - это « Улучшенный либерал» Джона Грубера « Шаблон точного регулярного выражения для сопоставления URL-адресов» . В настоящее время размещена однострочная версия:

(?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`!()\[\]{};:'".,<>?«»“”‘’]))

Джон также, кажется, поддерживает суть здесь , хотя его запись в блоге намного лучше объясняет его тестовый корпус и ограничения шаблона регулярного выражения.

Если вы хотите реализовать выражение из командной строки, вы можете оказаться ограничены используемым механизмом регулярных выражений или проблемами с цитированием оболочки. Я нашел Ruby-скрипт как лучший вариант, но ваш пробег может отличаться.

CodeGnome
источник
2
Пожалуйста, включите регулярное выражение в свой ответ вместо ссылки на него.
Тердон
@terdon, полное регулярное выражение составляет около 60 строк.
vonbrand
2
@ Vonbrand Я знаю, я видел это. Мы просто стараемся избегать ссылок на внешние ресурсы. Весь смысл сайтов SE в том, чтобы быть вики. Что если блог, на который вы ссылаетесь, отключится? Ваш ответ станет бесполезным. Во всяком случае, 60 строк - это не так уж много, а для удобства чтения - всего 60 строк.
Terdon
2

Проблема с сопоставлением URL-адресов заключается в том, что в URL-адресе может быть что угодно :

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

Как вы можете видеть, (действительный) URL выше , содержит $, ?, #, &, ,, .и :. По сути, единственное, что вы можете быть уверены, что URL-адрес не содержит, это пустое пространство. Имея это в виду, вы можете извлечь ваши URL с помощью простого шаблона:

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

\SСоответствует любым некосмическим символам в Perl совместимых регулярных выражений (PCREs), то -Pактивируется PCREs для grepи -oделает печать только совпадающий отрезок линии.

Тердон
источник
0

Я бы пошел на цепочку, но немного по-другому. Если у вас есть текстовый фрагмент, подобный вашему, в текстовом файле strings.txt, вы можете сделать следующее:

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

Объяснение:

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 

Поскольку существует вероятность того, что URL-адрес может не работать, вы можете выполнить дополнительную проверку ошибок с вашим URL-адресом. Например, wget -p URL -O /dev/null- он напечатает совершенно другие коды ошибок, если URL-адрес недоступен, так что вы можете настроить цикл для обработки списка ссылок и вывода их статуса достоверности.

Если вы в конечном итоге извлекаете ссылки из HTML-файлов, sedв особых случаях могут возникнуть проблемы . Как было предложено в забавном посте, который вы, вероятно, уже видели - может быть, лучше не использовать регулярные выражения, а механизм парсера html. Одним из таких легко доступных парсеров является только текстовый браузер lynx(доступный на любом Linux). Это позволяет мгновенно вывести список всех ссылок в файле, а затем просто извлечь нужные URL-адреса с помощью grep.

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

Однако это не будет работать с большинством искаженных HTML-файлов или текстовых фрагментов со ссылками.

r0berts
источник
-1

Просто egrep -o 'https?://[^ ")]+'

который будет включать url()и "http"

Роберто Берто
источник
3
Чем это отличается от ответа devnull? Я надеюсь, вы понимаете, что использование egrepне рекомендуется.
Anthon
Если у вас есть улучшения по сравнению с существующим ответом, вы можете вернуться по ссылке «поделиться» под этим ответом. Смотрите также страницы справки
Джефф Шаллер
-1
cat text-file.txt | grep -Eo '(https?|ftp|file)://[-A-Za-z0-9\+&@#/%?=~_|!:,.;]*[-A-Za-z0-9\+&@#/%=~_|]'

альтернативно добавьте команду SED, чтобы сохранить ее в файле CSV:

| sed 's/;/<tab>/g' > file.csv
MakoBuk
источник