Название: Регулярки Отправлено: Igors от Май 17, 2015, 07:34 Добрый день
Наконец-то (первый раз в жизни) мне понадобились регулярные выражения! :) Нужно очень немного - "джокеры" * - любое кол-во любых символов ? - один любое символ - уметь искать "полные слова" (с джокерами и без) Ладно, открываю букварь, вроде мне подходит QRegExp::Wildcard (PatternSyntax). Но тут растерялся Цитировать // To test a string against a wildcard expression, use exactMatch(). For example: ВопросыQRegExp rx("*.txt"); rx.setPatternSyntax(QRegExp::Wildcard); rx.exactMatch("README.txt"); // returns true rx.exactMatch("welcome.txt.bak"); // returns false 1) Так что, с Wildcard можно юзать только exactMatch, остальное не будет работать или как? 2) Во втором вызове (где returns false) мне надо чтобы находило (напр поиск "contains"). Как это сделать? 3) Чтобы искало полные слова - надо "обрамлять" \\b, правильно? Спасибо Название: Re: Регулярки Отправлено: kambala от Май 17, 2015, 12:16 1) похоже на то
2) ну придется звездочками хитрить: "*.txt*" 3) \b в Wildcard не прокатит. регулярка "\\b.+?\\.txt.*?\\b" (для QRegExp вместо знаков вопроса надо использовать setMinimal(true), QRegularExpression таким не страдает) Название: Re: Регулярки Отправлено: Igors от Май 17, 2015, 13:31 1) похоже на то Поэкспериментировал, работает indexIn, QString::indexOf(QRegExp). Слово не выделяет (\\b не понимает как и любой слеш), ну не беда, сам написал. 2) ну придется звездочками хитрить: "*.txt*" 3) \b в Wildcard не прокатит. регулярка "\\b.+?\\.txt.*?\\b" (для QRegExp вместо знаков вопроса надо использовать setMinimal(true), QRegularExpression таким не страдает) Тут такие проблемы 1) Строку паттерна вводит юзер, поэтому выбран WildCard. Как-то строку "транслировать" (чтобы задействовать "полный" режим) - думал, но не видно как 2) Было бы хорошо использовать "номер" (напр символ #). Пример: есть 100 объектов с именами "Sphere 1", "Sphere 2",... "Sphere 100". Или вообще имя одно "Sphere" у всех. Полезной опцией была бы возможность убрать/добавить "номера" (1..100). Как это половчее сделать? Спасибо Название: Re: Регулярки Отправлено: kambala от Май 17, 2015, 14:16 1)
Название: Re: Регулярки Отправлено: Bepec от Май 17, 2015, 15:00 Я использую deelx.h библиотечку, один ашник, поддерживает полностью все regExp, чисто сишный интерфейс.
Конечно, для себя имеется небольшая обвязочка на Qt, но вам наверно пойдёт и так :) PS Qt-шный regexp до пятерки отвратный :) Название: Re: Регулярки Отправлено: Igors от Май 17, 2015, 15:29 1) Не зрозумiв. На всяк випадок ще раз перевiрив ? - робить добре
2) "Sphere ?\\d{0,3}?" — совпадет со "Sphere", "Sphere ", "Sphere123", "Sphere 999". Если жестко максимум 100, то можно что-то типа "Sphere ?(?:\\d{0,2}|100)?", но лучше погуглить :) — уверен, таких вопросов поднималась куча Жестко не будет, есть варианты - напр нумерация в рамках объекта-парента или глобальная. Если просто "добавить в хвост" (убрать из хвоста) то можно без всякого RegExp. Но все так от него пищат что я аж засомневался - ну а вдруг есть "более элегантные решения" (а я тут прусь с велосипедом :)). Напр возможен такой случайКод: Sphere 1 Red Цитировать Sphere # * Это паттерн что ввел юзер. Если бы можно было выцепить "решетку" (число) чтобы только его заменить/удалить Название: Re: Регулярки Отправлено: kambala от Май 17, 2015, 23:34 1) . (точка) означает любой символ в регулярном выражении, т.е. то же самое, что и ? в вайлдкарде
"Sphere # *" -> "Sphere (\\d+).*", число будет в rx.cap(1) Название: Re: Регулярки Отправлено: Igors от Май 18, 2015, 10:46 Непонятки с replace. Неужели замещающая строка может быть только фиксированной? Напр такой паттерн
Цитировать ? * * Вот я хочу заменить только первую "звездочку" не трогая остальное. Как мне это сделать? Если использовать просто " * " то это может соответствовать совсем другому контексту (во всей строке)Спасибо Название: Re: Регулярки Отправлено: kambala от Май 18, 2015, 10:55 чтобы регулярка совпала со звездочкой, надо эту звездочку экранировать бэкслэшем. хотя не совсем понятно зачем для замены первого вхождения звездочки в строке использовать регулярку…
Название: Re: Регулярки Отправлено: Igors от Май 18, 2015, 11:29 чтобы регулярка совпала со звездочкой, надо эту звездочку экранировать бэкслэшем. хотя не совсем понятно зачем для замены первого вхождения звездочки в строке использовать регулярку… Не выходит, ставлю \\ вообще не находит. Фраза из букваряЦитировать In the mode Wildcard, the wildcard characters cannot be escaped. In the mode WildcardUnix, the character '\' escapes the wildcard. Разницы между Wildcard/WildcardUnix пока не увидел. Что здесь означает "escaped"?Спасибо Название: Re: Регулярки Отправлено: kambala от Май 18, 2015, 14:02 escaped = бэкслэш перед спец. символом. значит матчнуть символ * или ? в вайлдкарде можно только в режиме WildcardUnix, дописав перед символом бэкслэш
Название: Re: Регулярки Отправлено: Igors от Май 18, 2015, 14:54 escaped = бэкслэш перед спец. символом. значит матчнуть символ * или ? в вайлдкарде можно только в режиме WildcardUnix, дописав перед символом бэкслэш А каков должен быть эффект этого "матчения"? :) НапрЦитировать Sphere * В чем разница?Sphere \\* Название: Re: Регулярки Отправлено: kambala от Май 18, 2015, 16:13 в режиме WildcardUnix первое матчнет "Sphere ляляля", а второе — "Sphere *"
Название: Re: Регулярки Отправлено: Igors от Май 18, 2015, 17:07 в режиме WildcardUnix первое матчнет "Sphere ляляля", а второе — "Sphere *" Понял, спасибо. К сожалению, пользы от этого немного :)Название: Re: Регулярки Отправлено: Igors от Май 19, 2015, 11:58 Хотелось бы иметь возможность "удалять слово". Пример
Цитировать arm_lo 1 Найти легко, паттерн "arm_* *". Но как мне удалить номера (1, 2)?arm_hi 2 Название: Re: Регулярки Отправлено: Bepec от Май 19, 2015, 16:05 хм. удалить можно, используя предпросмотр назад и вперед.
Т.е. (?<=arm_..)* найдёт лишь 1 и 2. Ну и зная их позиции спокойно удаляем. ссылка на вики, раздел "Просмотр вперёд и назад" https://ru.wikipedia.org/wiki/%D0%A0%D0%B5%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D0%B5_%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F#.D0.93.D1.80.D1.83.D0.BF.D0.BF.D0.B8.D1.80.D0.BE.D0.B2.D0.BA.D0.B0_.D0.B1.D0.B5.D0.B7_.D0.BE.D0.B1.D1.80.D0.B0.D1.82.D0.BD.D0.BE.D0.B9_.D1.81.D0.B2.D1.8F.D0.B7.D0.B8 PS в Qt4 QRegExp не поддерживал эту возможность. Название: Re: Регулярки Отправлено: kambala от Май 19, 2015, 17:51 в «регулярном» режиме это делается легко через захват числа в () и QRegExp::pos()
Название: Re: Регулярки Отправлено: Igors от Май 20, 2015, 08:34 в «регулярном» режиме это делается легко через захват числа в () и QRegExp::pos() Но не в wildcard режиме. Ну ничего, перебьютсяТ.е. (?<=arm_..)* найдёт лишь 1 и 2. Ну и зная их позиции спокойно удаляем. Ну расчет на юзера который может и про джокер-звездочку никогда не слыхал - он вводит пвттернНазвание: Re: Регулярки Отправлено: Bepec от Май 20, 2015, 10:30 Ну так напишите собственный псевдоязык.
А дальше уже преобразуйте в regExp. PS какой то язык пользователь всё равно должен будет запомнить, иначе не сможет работать с программой. Название: Re: Регулярки Отправлено: Kurles от Май 20, 2015, 16:03 Хотелось бы иметь возможность "удалять слово". Пример Ну если именно с помощью регекспов, то первое, что в голову пришло:Цитировать arm_lo 1 Найти легко, паттерн "arm_* *". Но как мне удалить номера (1, 2)?arm_hi 2 Код Но тут уже не Wildcard matching. Название: Re: Регулярки Отправлено: Igors от Май 20, 2015, 16:58 Ну так напишите собственный псевдоязык. Были мысли в этом направлении ("решетка"), но отказался - при малейшем наращивании ф-ционала светит "тот самый велосипед"А дальше уже преобразуйте в regExp. PS какой то язык пользователь всё равно должен будет запомнить, иначе не сможет работать с программой. Ну я пользовался "звездочкой" в Norton Commander не подозревая о существовании регулярок.Ну если именно с помощью регекспов, то первое, что в голову пришло: А как юзверь в UI введет "двойку" которая нужна для cap(2) ?Код Но тут уже не Wildcard matching. Хорошо, пусть более скромная задача Цитировать ren *.cpp *.cp1 Это работает напр в Far. Как добиться того же? Т.е. юзер вводитЦитировать Search for: *.cpp Replace with: *.cp1 Название: Re: Регулярки Отправлено: kambala от Май 20, 2015, 17:06 как преобразовать вайлдкард в полноценную регулярку я уже писал, разберем на примере:
1) вайлдкард *.cpp превращаем в регулярку (.+)\.cpp (можно и .* вместо .+, но вряд ли нас интересуют файлы с пустым именем: ".cpp") 2) имя файла в rx.cap(1) 3) результат: rx.cap(1) + ".cp1" Название: Re: Регулярки Отправлено: Bepec от Май 20, 2015, 17:17 Вы опять хотите чтобы пользователь без знания wildcard regexp и простейшего псевдоязыка мог пользоваться вашей программой? Мечтатель :)
Название: Re: Регулярки Отправлено: Igors от Май 20, 2015, 17:58 как преобразовать вайлдкард в полноценную регулярку я уже писал, разберем на примере: Та же проблема что и в ответе Kurles, только 1 вместо 2. Но ведь может быть и так1) вайлдкард *.cpp превращаем в регулярку (.+)\.cpp (можно и .* вместо .+, но вряд ли нас интересуют файлы с пустым именем: ".cpp") 2) имя файла в rx.cap(1) 3) результат: rx.cap(1) + ".cp1" Цитировать ren test.c* test1.c* или такЦитировать ren *.c* *.cpp Название: Re: Регулярки Отправлено: kambala от Май 20, 2015, 19:16 где проблема? каждую звездочку мы заменяем на (.+), индексы для cap() начиная с 1 — это номер скобок если считать слева направо.
"asd(.+)qwe(.+)zxc" совпадет например с "000asd123qwe321zxcлрнпии", где rx.cap(0) = asd123qwe321zxc (полное совпадение), rx.cap(1) = 123, rx.cap(2) = 321 для ren *.c* *.cpp браться будет только rx.cap(1) Название: Re: Регулярки Отправлено: Igors от Май 21, 2015, 06:09 где проблема? каждую звездочку мы заменяем на (.+), индексы для cap() начиная с 1 — это номер скобок если считать слева направо. Да, мы можем выцепить все куски которые найдены на месте джокеров - ну а толку? Это же совсем не значит что все их надо менять, это определяется выходным паттерном задаваемым пользователем (replace with). Тот же пример "asd(.+)qwe(.+)zxc" совпадет например с "000asd123qwe321zxcлрнпии", где rx.cap(0) = asd123qwe321zxc (полное совпадение), rx.cap(1) = 123, rx.cap(2) = 321 для ren *.c* *.cpp браться будет только rx.cap(1) Цитировать ren test.c* test1.c* Требуется заменить test на test1. Какому cap(?) он соответствует? Еще пример Цитировать ren test*.c* tst0.c1 А здесь устраивает и та замена что в QString - но как это вычислить?Edit: более четко можно сформулировать так. Пусть есть строка поиска Цитировать Search for: test*.c* Но по ней мы ничего еще заменять не можем. В зависимости от строки заменыЦитировать Replace with: test1.c* Это будут 3 разные замены. И все они работают в командной строке, Far и др. Может это вообще не регулярки ???Replace with: test*.cpp Replace with: test.c По классике Цитировать Вот так всю жизнь и проживешь без собаки ... :)Название: Re: Регулярки Отправлено: kambala от Май 21, 2015, 10:23 Цитировать Может это вообще не регулярки естественно нет, это вайлдкардыв общем раз конечной целью является работа с вайлдкардами, то предлагаю полистать исходники баша и посмотреть как там это обрабатывается. фар же вроде тоже использует командную строку. Название: Re: Регулярки Отправлено: Igors от Май 23, 2015, 08:15 Цитировать Может это вообще не регулярки естественно нет, это вайлдкардыПришлось сделать самому (аттач). Попинайте Edit: исправил бажок, обновил (2) |