Модераторы: Partizan, gambit
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Alternation Constructs в .NET Regexp, Conditional (?(expression)yes|no)... 
V
    Опции темы
FiMa1
Дата 28.8.2008, 14:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 408
Регистрация: 23.9.2006

Репутация: нет
Всего: 6



Добрейшего времени суток, друзья.

Столкнулся со следующей проблемой:
Имеем следующую теорию Alternation Constructs, пытаюсь использовать '(?(expression)yes|no)' регулярное выражение. Входной текст: "abcdefg", пишу (?(abc)defg|"") - получаю 'No Matches' (конструктор регулярных выражений 'RAD Software Regular Expression Designer 1.4.7'). Если кто-нибудь сталкивался с подобным или знает в чем дело, помогите, пожалуйста.
PM   Вверх
Bishop
Дата 28.8.2008, 15:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 188
Регистрация: 3.6.2005
Где: Минск, Беларусь

Репутация: 6
Всего: 16



FiMa1, 

Вы хотите "abc" использовать как шаблон, а оно воспринимается как name. Укажите явно: (?(?<=abc)defg|"").

Grouping Constructs.
Синтаксис шаблонов — разделы Утверждения и Условные подмаски.
PM WWW ICQ   Вверх
FiMa1
Дата 28.8.2008, 16:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 408
Регистрация: 23.9.2006

Репутация: нет
Всего: 6



Цитата(Bishop @ 28.8.2008,  15:37)
FiMa1, 

Вы хотите "abc" использовать как шаблон, а оно воспринимается как name. Укажите явно: (?(?<=abc)defg|"").

Grouping Constructs.
Синтаксис шаблонов — разделы Утверждения и Условные подмаски.

Bishop, большое спасибо!

Я пробежался глазами по приведенным ссылкам, пока не уяснил для себя, что можно считать "именем"? Никогда до этого сталкивался с этим понятием.

(?(name)yes|no) 
Matches the "yes" part if the named capture string has a match; otherwise, matches the "no" part. The "no" part can be omitted. If the given name does not correspond to the name or number of a capturing group used in this expression, the alternation construct is interpreted as an expression test (described in the preceding row of this table).

Не подскажите вкратце, если есть минутка. Был бы еще больше признателен smile .

Это сообщение отредактировал(а) FiMa1 - 28.8.2008, 16:46
PM   Вверх
Bishop
Дата 28.8.2008, 19:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 188
Регистрация: 3.6.2005
Где: Минск, Беларусь

Репутация: 6
Всего: 16



FiMa1, группы (подмаски), т.е. выражения в скобках можно именовать, тогда к ним можно будет обращаться не по номерам, а по этим именам. 
Код
Match m = Regex.Match("[email protected]", @"(?<addr>.*?)@(?<host>.*?\..{2,})");
string msg = string.Format("{0}\n{1}\n{2}\n{3}",
    m.Groups[1].Value, // address
    m.Groups["addr"].Value, // address
    m.Groups[2].Value, // mail.ru
    m.Groups["host"].Value // mail.ru
);

В случае альтернатив:
Код
Regex.Match("abcdefgh", @"(?<name>abc)(?(name)de|.*)"); // abcde
Regex.Match("abcdefgh", @"(?<name>abc)(?(name1)de|.*)"); //abcdefgh

И это наиболее понятный способ их использования.
Я похоже ошибся в прошлом посте:
Код
Regex.Match("abcdefgh", @"(?(abc)abcde|.*)"); // abcde
Regex.Match("abcdefgh", @"(?(bc)abcde|.*)"); // abcdefgh

Т.е. все работает, но анализ идет четко с начала строки, как будто там не abc, а ^abc.
Код
Regex.Match("abcdefgh", @"(?(abc)f|.*)"); // bcdefgh

А этот результат объяснить не могу  smile .
PM WWW ICQ   Вверх
source777
Дата 28.8.2008, 21:51 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1878
Регистрация: 12.3.2007

Репутация: 4
Всего: 56



Цитата(Bishop @  28.8.2008,  19:15 Найти цитируемый пост)
Я похоже ошибся в прошлом посте:
...
Т.е. все работает, но анализ идет четко с начала строки, как будто там не abc, а ^abc.

В этом посте ты тоже к сожалению ошибся, это заметно, например, на таком примере:
Код

Regex.Match("abcnoyes", @"(?(abc)yes|no)"); // no
Regex.Match("abcnoyes", @"(?(.*)yes|no)"); // yes

Т.е. во всех 3 нижних строках кода из твоего поста фактически срабатывает условие "no", но срабатывает как-то глючно, в чём ты впрочем не виноват  smile 


--------------------
Если бы программистам платили за то, чтобы убирать код из программы вместо того, чтобы добавлять его, программы были бы намного лучше © Николас Негропонте
PM MAIL   Вверх
Bishop
Дата 29.8.2008, 01:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 188
Регистрация: 3.6.2005
Где: Минск, Беларусь

Репутация: 6
Всего: 16



source777, 
В первой из трёх нижних строк выполняется yes. А в остальных всё тоже правильно, то есть не "глючно" smile
Код
(?(expression)yes|no)

Я почему-то подумал (и похоже, ты тоже), что эта конструкция работает по логике if-then-else: если expression истинно, то ищется шаблон yes, иначе шаблон no. Но это не так. 
Выражение "yes" — это вся часть (expression)yes. А (expression), если не указано явно, это (?=expression). Фактически, это сокращенная запись, которую можно развернуть в:
Код
(?(expr)yes|no) === (?:(?=expr)yes|no)

И тогда все ясно с примерами:
Место (abc) === (?=abc) в строке находится "(_здесь_)abcdefgh"
Код
Regex.Match("abcdefgh", @"(?(abc)abcde|.*)"); // abcde
Regex.Match("abcnoyes", @"(?(abc)yes|no)"); // no

Потому что:
Код
Regex.IsMatch("abcdefgh", @"(?=abc)abcde"); // true
Regex.IsMatch("abcnoyes", @"(?=abc)yes"); // false


PM WWW ICQ   Вверх
FiMa1
Дата 29.8.2008, 08:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 408
Регистрация: 23.9.2006

Репутация: нет
Всего: 6



Bishop, source777, большое спасибо за участие! Теперь понятно с именами и почему я с ними не сталкивался, я не использовал регулярные выражения непосредственно в коде на C#.
PM   Вверх
source777
Дата 29.8.2008, 10:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1878
Регистрация: 12.3.2007

Репутация: 4
Всего: 56



Цитата(Bishop @  29.8.2008,  01:51 Найти цитируемый пост)
Я почему-то подумал (и похоже, ты тоже), что эта конструкция работает по логике if-then-else: если expression истинно, то ищется шаблон yes, иначе шаблон no. 
да, это ты точно подметил. Хотя подобное заблуждение казалось вполне логичным  smile 

Однако, всё равно остались невыясненные моменты, например,
Код

Regex.Match("abcyesno", @"(?(yes)yes|no)"); // yes
Regex.Match("abcyesno", @"(?(yes)yes|.*)"); // abcyesno
Regex.IsMatch("abcyesno", @"(?=yes)yes"); // true

Казалось бы, поскольку IsMatch == true, то в Match.Value всегда должно быть "yes", в независимости от "no" - части, однако это не так... smile 
Причём если использовать в качестве входной строки "yesno", то так и будет, однако такая жёсткая привязка в началу строки не всегда подходит, в качестве воркэраунда насколько я выяснил сработает: 
Код

Regex.Match("abcyesno", @"(?(.*yes)yes|.*)"); // т.е. просто пропускаем начало строки вплоть до нужного нам шаблона...
 


--------------------
Если бы программистам платили за то, чтобы убирать код из программы вместо того, чтобы добавлять его, программы были бы намного лучше © Николас Негропонте
PM MAIL   Вверх
Bishop
Дата 29.8.2008, 19:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 188
Регистрация: 3.6.2005
Где: Минск, Беларусь

Репутация: 6
Всего: 16



source777, 
Цитата(source777 @  29.8.2008,  10:54 Найти цитируемый пост)
Казалось бы, поскольку IsMatch == true, то в Match.Value всегда должно быть "yes", в независимости от "no" - части, однако это не так...  

Не, не так. Оно не ищет условие, идет последовательный анализ строки и, если условие ложно, а часть NO в этой позиции находит совпадение, разбор прекращается. Смотри:
Код
Regex.Match("abcyesno", @"(?(yes)yes|.*)"); // abcyesno

Причем (yes) это сокращенная запись утверждения (?=yes).
Разбор начинается с начала строки: на символе "a" (?=yes) ложно — переход к части NO; .* в этой позиции совпадает со всей строкой — это результат.
Код
Regex.Match("abcyesno", @"(?(yes)yes|no)"); // yes

Здесь разбор идет так: "a" — (?=yes) ложно, часть NO в текущей позиции не совпадает; "b" — тоже; "c" — тоже; "y" — (?=yes) истинно, (?=yes)yes совпадает — это результат.
И правильный вариант:
Код
Regex.Match("abcyesno", @"(?(.*yes)yes|.*)");

Этапы разбора: "a" — (?=.*yes) истинно, но (?=.*yes)yes не совпадает, .* пропускается; "b" — тоже; "c" — тоже; "y" — (?=.*yes) истинно, (?=.*yes)yes совпадает — это результат.
Тогда всё ясно с непонятным результатом выражения из моего позапрошлого поста:
Код
Regex.Match("abcdefgh", @"(?(abc)f|.*)"); // bcdefgh

Разбор: "a" — (?=abc) истинно, но (?=abc)f не совпадает, .* пропускается; "b" — (?=abc) ложно, .* совпадает с "bcdefgh" — это результат. Не вся строка, т.к. "a" уже пропущена, а разбор без особой нужды в обратную сторону не идёт.

Может я ошибаюсь на счёт внутренней работы regex engine, но концептуально оно вот так.
Т.е. не ищется совпадение expression по всей строке (как мы думали), оно вычисляется на общих основаниях по мере разбора строки. От простой альтернативы отличается тем, что пока условие истинно совпадения в блоке NO не ищутся. Вот:
Код
Regex.Match("abcyes abcno", @"(?(abc)abcno|abcyes)");  // abcno
Regex.Match("abcyes abcno", @"(?:abcno|abcyes)"); // abcyes


В описании этапов под буквами подразумеваются Zero-width позиции перед ними.
Пытался объяснить, надеюсь не запутал ещё больше smile 

Это сообщение отредактировал(а) Bishop - 29.8.2008, 19:53
PM WWW ICQ   Вверх
source777
Дата 30.8.2008, 16:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1878
Регистрация: 12.3.2007

Репутация: 4
Всего: 56



Bishop, спасибо, более менее прояснилась ситуация  smile 


--------------------
Если бы программистам платили за то, чтобы убирать код из программы вместо того, чтобы добавлять его, программы были бы намного лучше © Николас Негропонте
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема »


 




[ Время генерации скрипта: 0.0545 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.