Russian Qt Forum

Qt => Вопросы новичков => Тема начата: Smogg от Июль 16, 2013, 23:22



Название: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: Smogg от Июль 16, 2013, 23:22
Ниче не понимаю...

вот такая строчка:
https://oauth.vk.com/blank.html#access_token=17a6ab0190a8ad75c2f3dffa713c3708c6943dc1562cdee85252f33a8fdabdbc803d33e7aa841bc4e9b70&expires_in=86400&user_id=14266994

как из нее получить два Qstring'a - sAccess_token и sExpires_in?

Код:
QRegExp rx;
rx.setPattern("(?:access_token=(\\w+))(?:expires_in=(\\d+))");

if (y = rx.indexIn(s) ) {
sAccess_token = rx.cap(1);
sExpires_in = rx.cap(2);
}
не работает


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: kambala от Июль 16, 2013, 23:52
Код
C++ (Qt)
QRegExp rx("access_token=([a-z\\d]+)&expires_in=(\\d+)");
rx.setMinimal(true);
это если порядок параметров гарантирован. и то, тут можно и обычным поиском QString::indexOf() обойтись.

если же порядок параметров неизвестен (например expires_in идет перед access_token и между ними еще что-нибудь внутри), то лучше выполнить два отдельных поиска (опять же, хоть через QString::indexOf()).


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: thechicho от Июль 17, 2013, 06:05
QRegExp rx; rx.setMinimal(true); rx.setCaseSensitivity(Qt::CaseInsensitive);
rx.setPattern("access_token=([^&]+).*&expires_in=([^&]+).*$");

и как сказал kambala лучше выполнять два отдельных поиска.

to kambala, через QString::indexOf() как это будет выглядеть?


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: Bepec от Июль 17, 2013, 07:14
Две строки. Поиск первого вхождения, поиск второго вхождения, вырезание результатов.

Всё просто.

PS я бы indexOf использовал. Не люблю регЭкспы.


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: thechicho от Июль 17, 2013, 09:30
Верес, код в студию.


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: Bepec от Июль 17, 2013, 09:51
Код:
QString tmp = "https://oauth.vk.com/blank.html#access_token=17a6ab0190a8ad75c2f3dffa713c3708c6943dc1562cdee85252f33a8fdabdbc803d33e7aa841bc4e9b70&expires_in=86400&user_id=14266994";

int i1 = (tmp.indexOf("token="));
int i2 = (tmp.indexOf("&expires_in="));
int i3 = (tmp.indexOf("&user_id="));

QString sAccess_token = tmp.mid(i+6, i2);
QString sExpires_in = tmp.mid(i2+12, i3);
При желании можно ужать в две строки и без промежуточных переменных.

PS тот кто начнёт говорить про "гибкость" и "расширяемость" - огурец.


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: thechicho от Июль 17, 2013, 10:57
tmp.mid(i+6, i2);
tmp.mid(i2+12, i3);
отжег ;D


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: Igors от Июль 17, 2013, 11:25
Код:
QString tmp = "https://oauth.vk.com/blank.html#access_token=17a6ab0190a8ad75c2f3dffa713c3708c6943dc1562cdee85252f33a8fdabdbc803d33e7aa841bc4e9b70&expires_in=86400&user_id=14266994";

int i1 = (tmp.indexOf("token="));
int i2 = (tmp.indexOf("&expires_in="));
int i3 = (tmp.indexOf("&user_id="));

QString sAccess_token = tmp.mid(i+6, i2);
QString sExpires_in = tmp.mid(i2+12, i3);
При желании можно ужать в две строки и без промежуточных переменных.

PS тот кто начнёт говорить про "гибкость" и "расширяемость" - огурец.
Это больше подходит для тех кто лепит 6 и 12 прямо в код (убивать надо), попутал парвметры mid, втулил нафиг не нужные скобки и никак не позаботился об обработке ошибок.


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: Bepec от Июль 17, 2013, 11:45
thechicho, Igors - специально для вас я написал это в браузере, по памяти, максимально быстро, дабы передать примерное представление о коде.

PS переделка по умному займёт минуты полторы (90 секунд).  С отсутствием магических 6/12. Попробуйте - у вас должно получиться :D Займёт правда 4 строки.

PPS умение или религия не позволяет вам понять, что это пример кода?  ::)

update: Igors религия не позволяет. Это я уже знаю. Так что последний вопрос к thechicho.


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: kambala от Июль 17, 2013, 11:55
2Bepec: искать вместе с амперсандом не надо (вдруг во входной строке порядок параметров будет другой).

ну, и как уже сказали выше, магические числа — это нехорошо, лучше искомые строки засунуть в переменные и прибавлять их length()/qstrlen(). если показываешь пример, то показывай правильный, тем более что он бы занял не намного больше времени.
PS переделка по умному займёт минуты полторы (90 секунд).


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: thechicho от Июль 17, 2013, 11:56
мне просто интересно было как это выглядит с QString::indexOf(). чтобы сравнить - может действительно так проще, чем регулярками парсить ;D


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: Bepec от Июль 17, 2013, 11:59
Ну уж извините, не было у меня тогда большого желания писать верный код. Было желание показать примерный алгоритм.

PS как то помню сравнивал RegExp с indexOf - цель была парсинг параметров по разделителю. RegExp был медленнее чем indexOf почему то.


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: thechicho от Июль 17, 2013, 12:07
QRegExp может и программу "подвесить навеки", если регулярку кривую написать. но все равно на мой взгляд лучше для парсинга, чем строковые (QString) функции.
если нужна супер-мега производительность, наверное Qt не лучший вариант для решения задачи.


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: Smogg от Июль 17, 2013, 22:56
PS я бы indexOf использовал. Не люблю регЭкспы.
Я тоже ;) Но в данном случае правильнее и масштабируемее через регулярности, безотносительно моих симпатий(

rx.setPattern("access_token=([^&]+).*&expires_in=([^&]+).*$");
Что тут происходит пo моему разумению... :
  • Отсутствие ^ в начале паттерна говорит, что перед первым соответствие регэкспу может быть что и сколько угодно.
  • access_token=
    Потом прямо вписанный access_token= означает именно такой порядок символов.
  • ([^&]+)
    Дальше открываются скобки и они означают начало нового экземпляра поиска по регэкспу и поэтому можно опять использовать ^?
    Как прочитал и запомнил, в квадратных скобках может быть перечисление без пробелов вариантов вхождений или интервалы через тире. Амперсанд же по справке не относится к служебным символам. Что & тут означает?
    + - как минимум одно вхождение предыдущего выражения.
  • Потом очередное подвыражение: .*&expires_in
    каковое означает вхождение любого символа не важно сколько раз, пока не найдется очередной plaintext &expires_in, который начинается с &, использованный совсем в другом смысле в квадратных скобках...
  • ([^&]+)
    дальше не понятный мне дзен в скобка
  • .*$
    есть ли необходимость явно указывать, что до конца строки может быть еще что-то?

Еще один вопрос:
Как складывать в QStringList несколько соответствий одному и тому же регекспу?


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: tester64 от Июль 17, 2013, 23:21
Если очерёдность известна, то например так:
Код
C++ (Qt)
QRegExp rx(".+(?:access_token=([0-9a-f]+)(?:&|$)).*(?:expires_in=(\\d+)(?:&|$)).*");
if (rx.exactMatch(s)) { sAccess_token = rx.cap(1); sExpires_in = rx.cap(2); }


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: kambala от Июль 17, 2013, 23:33
Цитировать
регулярности
интересное слово какое :)
Цитировать
Что тут происходит пo моему разумению...
дзен можно познать тут: http://qt-project.org/doc/qt-4.8/qregexp.html#details
Цитировать
есть ли необходимость явно указывать, что до конца строки может быть еще что-то?
нет
Цитировать
Как складывать в QStringList несколько соответствий одному и тому же регекспу?
не совсем ясна суть вопроса. можно пример?


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: tester64 от Июль 17, 2013, 23:42
Метода вида QStringList occurences(QString, QRegExp) нет.
Можно так:
Код
C++ (Qt)
QRegExp rx(...);
QStringList list;
for (int pos = 0; (pos = rx.indexIn(str, pos)) != -1; pos += rx.matchedLength()) list += rx.cap(1);


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: thechicho от Июль 18, 2013, 07:20
регулярки мощный инструмент и писать одно и то же ими можно по-разному.
я пишу таким образом:
rx.setPattern("access_token=([^&]+).*&expires_in=([^&]+).*$");
[^&]+ - все что угодно, кроме &
.* - все что угодно или ничего

^ - начало строки
[^abc] - все что угодно кроме a или b или c
[abc] - a или b или c

если написать
&expires_in=([^&]+)"); - захватит только 1 символ
&expires_in=([^&]+).*$"); - захватит все, что нужно

было бы шикарно, если после записи
[^&]+
не надо было ничего писать. регулярка бы сама парсила все до знака &.
но стоит rx.setMinimal(true);
и QRegExp почему-то парсит только первый символ
если добавить что-нибудь
[^&]+blabla
тогда парсит все до первого знака &

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


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: Bepec от Июль 18, 2013, 08:21
QRegExp != RegExp.

Я им давно не пользуюсь именно из-за его обрезанности (QRegExp). Есть многие другие библиотечки для RegExp с полной поддержкой стандарта, типа deelx.


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: kambala от Июль 18, 2013, 11:35
2thechicho: не знаю где ты такое вычитал, но никаких .*$ не нужно лепить в конец строки. простой тестовый пример:
Код
C++ (Qt)
   QRegExp rx("test=([^&]+)&qwerty");
   QString s("asdtest=234dfgjknwedfrgfg ee434---555!@#&qwerty");
   if (rx.indexIn(s) != -1)
       qDebug() << rx.cap(1); // 234dfgjknwedfrgfg ee434---555!@#

2Bepec: для большинства задач QRegExp вполне подходит. какие ты фичи регулярок используешь, которых нету в QRegExp?


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: thechicho от Июль 18, 2013, 13:18
напиши вот так и поймешь, что я имел в виду
QRegExp rx("test=([^&]+)");

//Я им давно не пользуюсь именно из-за его обрезанности (QRegExp)
что там обрезано то? меня полностью устраивает. можно сделать все, что нужно.


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: kambala от Июль 18, 2013, 15:12
напиши вот так и поймешь, что я имел в виду
QRegExp rx("test=([^&]+)");
написал. не понял.
Код:
Starting D:\Programming\Qt\hello-4_8_5_msvs2012_x86-Debug\debug\hello.exe...
"234dfgjknwedfrgfg ee434---555!@#"

Starting D:\Programming\Qt\hello-Desktop_Qt_5_1_0_MSVC2012_64bit-Debug\debug\hello.exe...
"234dfgjknwedfrgfg ee434---555!@#"


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: Bepec от Июль 18, 2013, 15:49
Допустим нет просмотра выражения вперед. Жадность выражения указывается не в регэкспе, а отдельным флагом класса. Т.е. нельзя создать полноценный регэкс из строки. Это и убило мои последние приятные впечатления от него :D


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: kambala от Июль 18, 2013, 18:04
Допустим нет просмотра выражения вперед
вперед ?= есть, нету ?<= назад.
Цитировать
Both zero-width positive and zero-width negative lookahead assertions (?=pattern) and (?!pattern) are supported with the same syntax as Perl. Perl's lookbehind assertions, "independent" subexpressions and conditional expressions are not supported.


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: thechicho от Июль 18, 2013, 20:23
Цитировать
Starting D:\Programming\Qt\hello-4_8_5_msvs2012_x86-Debug\debug\hello.exe...
"234dfgjknwedfrgfg ee434---555!@#"

Starting D:\Programming\Qt\hello-Desktop_Qt_5_1_0_MSVC2012_64bit-Debug\debug\hello.exe...
"234dfgjknwedfrgfg ee434---555!@#"

rx.setMinimal(true); стоит?

(?=E)   Positive lookahead. This assertion is true if the expression matches at this point in the regexp. For example, const(?=\s+char) matches 'const' whenever it is followed by 'char', as in 'static const char *'. (Compare with const\s+char, which matches 'static const char *'.)
(?!E)   Negative lookahead. This assertion is true if the expression does not match at this point in the regexp. For example, const(?!\s+char) matches 'const' except when it is followed by 'char'.

"<div>(?:.(?!<div))+</div>"
пожалуйста, все есть.


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: kambala от Июль 18, 2013, 20:57
Цитировать
Starting D:\Programming\Qt\hello-4_8_5_msvs2012_x86-Debug\debug\hello.exe...
"234dfgjknwedfrgfg ee434---555!@#"

Starting D:\Programming\Qt\hello-Desktop_Qt_5_1_0_MSVC2012_64bit-Debug\debug\hello.exe...
"234dfgjknwedfrgfg ee434---555!@#"

rx.setMinimal(true); стоит?
нет, не стоит, я же привел код выше.

с ним да, захватывает лишь первый символ. я так понимаю в этом и состоит «нежадность»: раз дальше ничего не указано, то он и нежадно захватывает необходимый минимум, т.е. один символ (из-за +). с * так вообще ничего захватывать не будет. и это не баг.


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: thechicho от Июль 18, 2013, 21:05
asdtest=234dfgjknwedfrgfg ee434---555!@#&qwerty&blabla

нежадность
asdtest=234dfgjknwedfrgfg ee434---555!@#
жадность
asdtest=234dfgjknwedfrgfg ee434---555!@#&qwerty

разве нет?


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: kambala от Июль 18, 2013, 21:54
жадность
asdtest=234dfgjknwedfrgfg ee434---555!@#&qwerty
такой вариант точно невозможен из-за [^&].

кажется я понял почему так. «нежадность» означает совпасть по самому минимуму, т.е. когда совпадает "2" (это ведь не амперсанд), минимум выполнен (дальше ведь никаких символов указано), и значит можно заканчивать.


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: thechicho от Июль 18, 2013, 22:18
поэтому и нужно в конце .*$
а хотелось бы обойтись без этого. о чем я и писал выше.


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: kambala от Июль 18, 2013, 23:34
ну так не пиши [^&] да и все :) конструкция [^&]+?.*$ выглядит очень калично как по мне, скорее всего еще и оказывает ненужную нагрузку при поиске.


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: thechicho от Июль 19, 2013, 09:22
[a-z\\d]+
лучше так? вроде еще большая нагрузка будет.
так что нет, спасибо)

да и вообще насчет нагрузки я сказал уже.
qt не подходит, если нужна критическая скорость выполнения.


Название: Re: QRegExp, два подвыражения, предваряющихся известными строками
Отправлено: kambala от Июль 19, 2013, 12:04
лучше, потому что не нужно искать никому не нужное совпадение .*$. либо твой вариант без setMinimal.