Войти в систему

Home
    - Создать дневник
    - Написать в дневник
       - Подробный режим

LJ.Rossia.org
    - Новости сайта
    - Общие настройки
    - Sitemap
    - Оплата
    - ljr-fif

Редактировать...
    - Настройки
    - Список друзей
    - Дневник
    - Картинки
    - Пароль
    - Вид дневника

Сообщества

Настроить S2

Помощь
    - Забыли пароль?
    - FAQ
    - Тех. поддержка



Пишет dima_i ([info]dima_i)
@ 2013-05-12 13:35:00


Previous Entry  Add to memories!  Tell a Friend!  Next Entry
URL-matching regex
In case anybody needs it: here is a URL-matching regex, which is a modification of this one (surprisingly, I could not find good solutions on the web, and that was the best one I found). It seemed to have a minor bug, which is hopefully fixed in my version.

in python notation:

urlmatch=re.compile(ur'''(?i)\b(https?:// [^\s()<>]+
(?: \( [^\s()<>]* (?: \( [^\s()<>]* \) [^\s()<>]* )* \) [^\s()<>]*)*
( ( \( [^\s()<>]* (?: \( [^\s()<>]* \) [^\s()<>]* )* \) ) |
[^\s`!()\[\]{};:\'".,<>?\xab\xbb\u201c\u201d\u2018\u2019] ))''', re.X)


It only searches for URLs starting with "http://" or "https://" and with only two levels of nested brackets. If you need a more intelligent regex detecting strings like "www.example.com", you can use the beginning from the original code. Let me know if you find any examples where this regex fails.


(Добавить комментарий)


[info]chaource.livejournal.com
2013-05-12 22:53 (ссылка)
Something has to be done about those regexes... they are unreadable, hard to debug, hard to change or extend. My guess is that it's better to use context-free grammars to define regexes, and let the compiler create a huge and unreadable regex without your participation. I haven't ever implemented this technique yet but I'm going to look into it soon.

(Ответить) (Ветвь дискуссии)


[info]dima_i
2013-05-12 23:00 (ссылка)
I don't understand what you mean by "context-free grammars".
As for readability, sorry: I should have probably commented my regex as in the original code (see the link in the post). With such a commenting, the regex becomes just like any other code in any other language.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]chaource.livejournal.com
2013-05-12 23:12 (ссылка)
Sorry, I did not explain myself properly, I was just thinking aloud. If you are interested we could chat about this. I don't think that it helps to comment a regex. There are too many details - all those (...*)*)*)*, lots of repeated code, no way to organize anything -all this makes working with regexes difficult once you have to maintain a really large and complicated regex. Most of the time regexes are short and this problem does not arise.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]dima_i
2013-05-13 00:24 (ссылка)
Just replace "regex" with "C" in your last comment. Of course, you can organize by indentation just the same way you organize any other code.

(Ответить) (Уровень выше)


[info]meshko.livejournal.com
2013-05-15 06:28 (ссылка)
Is this going to be just lex/yacc? Which is often the opposite problem -- a lot of moving parts to solve a simple problem that can be solved by combining some regular expressions ;)

(Ответить) (Уровень выше)


[info]meshko.livejournal.com
2013-05-13 00:02 (ссылка)
http://stackoverflow.com/a/1732454/68105

(Ответить) (Ветвь дискуссии)


[info]dima_i
2013-05-13 00:20 (ссылка)
:) но вообще-то я не про html parsing, а про поиск URL в тексте.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]meshko.livejournal.com
2013-05-13 00:40 (ссылка)
Все равно, я бы искал https?:// и все.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]dima_i
2013-05-13 00:45 (ссылка)
Это-то понятно. Вопрос только в том, как алгоритмически определить, где URL-адрес (например, http://www.example.com) заканчивается.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]meshko.livejournal.com
2013-05-13 00:48 (ссылка)
Whitespace?

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]dima_i
2013-05-13 00:50 (ссылка)
В моем предыдущем комменте whitespace нет: после URL шла закрывающеяся скобка, и LJ отпарсил его правильно (линк вставился автоматически).

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]meshko.livejournal.com
2013-05-13 00:52 (ссылка)
whitespace или ( )
Keep it simple.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]dima_i
2013-05-13 00:55 (ссылка)
Что называется, ты сам напросился...

Я тоже думал, как ты, пока мой скрипт не попал вот на такое (пример URL из реальной жизни): http://wiki.nashtransport.ru/wiki/%D0%9F%D1%83%D1%88%D0%BA%D0%B8%D0%BD%D1%81%D0%BA%D0%B0%D1%8F_(%D1%81%D1%82%D0%B0%D0%BD%D1%86%D0%B8%D1%8F_%D0%BC%D0%B5%D1%82%D1%80%D0%BE,_%D0%9C%D0%BE%D1%81%D0%BA%D0%B2%D0%B0)

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]meshko.livejournal.com
2013-05-13 00:57 (ссылка)
Ну и что? Разве это можно решить? Как ты отличишь URL c ")" в конце от URL в скобках?

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]dima_i
2013-05-13 00:58 (ссылка)
Ну как, bracket matching, конечно.

(Ответить) (Уровень выше)


[info]dima_i
2013-05-13 00:59 (ссылка)
Этот линк был внутри href тагa, и закрывающая скобка -- часть URL. Видно, что LJ парсит его НЕправильно. Мой regex -- правильно.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]meshko.livejournal.com
2013-05-13 04:41 (ссылка)
Подожди, если он уже внутри href, то тебе надо парсить HTML, для этого есть терпимые библиотеки. Главное, что надо помнить -- это знаментый коан (или как там это назывется) от jwz: Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems.
Regular expressions вещь замечательная, в скрипте, или когда надо "что-то сделать". А вот в настоящей программе чаще всего они не лучший выбор.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]dima_i
2013-05-13 04:49 (ссылка)
Да, разумеется, в данном случае из href его можно было и регулярным образом извлечь. Но в принципе я хотел иметь "выделялку" URL из текста (не из html кода)-- в том же смысле, как это делает LJ, многие почтовые программы и т.д. У тебя есть альтернативные предложения, как это реализовать? Ни одно из твоих предложений до сих пор не предъявило удовлетворительного решения (удовлетворительное = правильное работающее в нормальных ситуациях, встречающихся в жизни). Я считаю, что именно для этой задачи regex -- лучший выбор (по крайней мере, я получил работающий код). Твоя критика мне непонятна.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]meshko.livejournal.com
2013-05-13 05:03 (ссылка)
Так а я не понял тогда как твой regexp отличит ) которая часть url, от ), которая часть текста. Ты сказал про bracket matching, но я не очень понял, что ты имеешь в ввиду.
Проблема с regexp, что если в этом ужасе на 4 строчки что-то не так, я поленюсь отлаживать и заменю на алогитм, записанный вручную. Я за всю свою жизнь один раз поддался соблазну и использовал нетривиальный regepx и через 3 месяца об этом пожалел.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]dima_i
2013-05-14 21:30 (ссылка)
Ну вот с этого и надо было начинать: что ты regex не любишь и не понимаешь, а не наезжать попусту. На самом деле, regex -- это и есть "алгоритм, записанный вручную", только в несколько необычных (зато коротких) обозначениях.
Как в regex записать пару скобок с каким-то содержимым -- ну очень просто: \([^()]*\) : такой regex найдет пару скобок, внутри которых любое содержимое без скобок (а одну закрывающую не найдет). Собственно, у этого товарища по ссылке очень хорошо откомментированный regex, я поэтому и не стал писать комментариев к своему, поскольку он состоит из тех же блоков, только несколько переставленных и подправленных.
Вообще скобки в URL -- это зло, но не мной придуманное. Поэтому приходится с этим как-то обращаться.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]meshko.livejournal.com
2013-05-14 21:44 (ссылка)
Ну, во-первых я не наезжаю, я высказываю свои соображения. Если это выглядит, как высказывание истины в последней инстанции, прошу прощения, и прошу учесть, что я (практически) никогда и ничего в таком формате сознательно не говорю, а если выходит так, то толко для красного словца.
Во-вторых я-то как раз regexp'ы люблю и все время ими пользуюсь.

Далее: RegEx -- это не запись алогритма, а запись определния regular language. Т.е. это такой интересный случай, когда ты что-то описываешь в такой виде, в котором компьютер может легко твою записть преобразовать в алгоритм, это что-то распознающий. Я говорю, что с точки зрнения читаемости этот формат не подходит для нетривиальных случаев.

Что касается конкретной проблемы со скобочками, меня беспокоят два аспекта:
1) это решение поддерживает только 2 уровня вложенных скобок (и, насколько я помню, решения в общем виде для любого уровня вложенности в regular languages доказуемо нет)
2) Не ясно, откуда взялись вложенные скобки?
(Вот как ты такое пропарсишь https://www.google.com/?q=:()

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]dima_i
2013-05-14 22:06 (ссылка)
Ну твои соображния выглядели как наезды :) типа задача простая, а я какую-то сложную дребедень написал.
1) А ты видел "in the wild" URL с более чем двумя уровнями вложенных скобок?
2) из практических наблюдений. Если кто пишет URL с непарными скобками -- сам виноват, увы. Вот видишь, LJ тоже не справился.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]meshko.livejournal.com
2013-05-15 06:47 (ссылка)
Как тебе такая идея -- искать до пробела, а потом если в конце есть непонятные символы типа пунктуации, то пробовать их по одному отбрасывать и посылать запрос, пока получишь 200.
У меня такое эстетическое соображение: если уж писать сложное, то с целью покрыть 99% случаев. А писать сложное для 90 или даже 95% обидно.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]dima_i
2013-05-15 11:52 (ссылка)
Ну я как бы не считаю, что вышеприведенный regex -- сложное, скорее наоборот. Твоя идея очень хороша, но требует посылать запрос, что в мою исходную посылку не входило.

(Ответить) (Уровень выше)


[info]chaource.livejournal.com
2013-05-13 16:01 (ссылка)
Со скобками, что ты два уровня предусмотрѣлъ - это остроумно. Но я только сейчасъ понялъ, изъ твоихъ послѣднихъ комментарiевъ, въ чёмъ собственно заключалась задача.

Вотъ meshko тоже говоритъ, что пожалѣлъ, когда использовалъ большой regex. Это оно самое. Есть нерѣшённая проблема, - regex трудно поддерживать и развивать. Сейчасъ твой скриптъ рѣшилъ задачу, и если его никогда не придётся передѣлывать, то всё замѣчательно и прекрасно. Но если черезъ годъ окажется, что какой-то странный URL не распознаётся, ты проведёшь полдня въ отладкѣ.

Въ чёмъ трудности работы съ регексами:

- у тебя въ головѣ есть идея о томъ, какъ и когда надо распознавать текстъ, но regex не отражаетъ эту идею - онъ является нагроможденiемъ скобокъ и звѣздочекъ. Когда твоя идея улетучится изъ головы, будетъ трудно что-то сдѣлать. Рѣшенiе - писать длинные комментарiи къ каждому кусочку регекса.

- когда регексъ долженъ что-то распознавать такое, что всё время повторяется то тутъ, то тамъ, ты вынужден повторять вѣсь кусочекъ кода регекса. Эти повторенiя нельзя "факторизовать", т.е. нельзя положить кусокъ регекса въ "регексную подпрограмму" и "вызывать" её много разъ изъ разныхъ мѣстъ. Поэтому регексы всегда длинные и нечитаемые. Это, я думаю, рѣшается лишь переходомъ къ context-free grammar, гдѣ и регексы, и болѣе мощные конструкцiи распознаются символически, и можно дѣлать "подпрограммы изъ регексовъ". Объ этомъ я и писалъ въ началѣ.

- Малѣйшая ошибка, пропущенная или лишняя звѣздочка - и ничего не работаетъ, и непонятно почему - отлаживать "по шагамъ" регексы нельзя. Рѣшенiе - написать очень много тестовъ, по два-три на каждый граничный случай, предусмотрѣнный твоимъ регексомъ, и прогонять всѣ тесты каждый разъ, когда ты что-то измѣняешь въ нёмъ.

(Ответить) (Ветвь дискуссии)


[info]dima_i
2013-05-13 20:12 (ссылка)
Это не я предусмотрел -- это товарищ, на которого я ссылку поставил. У него, собственно, все по полочкам разложено и откомментировано. Я просто исправил некоторый забавный баг в его коде.

(Ответить) (Уровень выше)