Forum Webscript.Ru
Программирование => Регулярные выражения => Тема начата: Phoinix от 16 Августа 2003, 14:22:45
-
Есть строка:
Some text 1 [s: Some text 2] Some text 3 [/s] Some text 4
и регуларное выражение:
$text =~s /.*\\[s\\:\\s*(.*)\\s*\\](.*?)|(.*\\n?)/$1/i;
В итоге получаю $text = "Some text 2", но меня смущает что закрывающихся скобок (]) две, не возникнет ли ситуации когда $text будет получать "Some text 2] Some text 3"? Или все-таки усложнить регулярное выражение до:
$text =~s /.*\\[s\\:\\s*(.*)\\s*\\].*\\[\\/s\\](.*?)|(.*\\n?)/$1/i;
-
Не проверяя свои размышления и принимая во внимание время в которое я это пишу, могу сказать следующее:
имхо, из-за жадности квантификатовров при первом шаблоне $text будет иметь значение Some text 2] Some text 3 [/s]
-
Извиняюсь, опечатался:
Some text 2] Some text 3 [/s
-
metton
Нет он возвращает правильное значение - Some text 2, но все-таки буду использовать второй вариант...
Просто интересно как возможно поведет себя регулярное выражение, на практике так как нужно, а в теории???
-
2Phoinix
Ответ, конечно, поздноват, но всё же...
Вот тест-код:
-----------------------------------------------------------------------------------
#!/usr/bin/perl -w
use strict;
use CGI qw(:all);
print header;
my $text = "Some text 1 [s: Some text 2] Some text 3 [/s] Some text 4";
print $text.\'
\';
$text =~ s/.*\\[s\\:\\s*(.*)\\s*\\](.*?)|(.*\\n?)/$1/i;
print $1.\'
\';
print $text.\'
\';
-----------------------------------------------------------------------------------
У меня, как я и предполагал, выдаёт:
-----------------------------------------------------------------------------------
Some text 1 [s: Some text 2] Some text 3 [/s] Some text 4
Some text 2] Some text 3 [/s
Some text 2] Some text 3 [/s Some text 4
-----------------------------------------------------------------------------------
Т.е. $1 выдаёт именно то что я сказал, а $text совсем не то, что тебе нужно.
И ещё: (.*?)
Тебе не кажется, что метасимвол \'?\' здесь излишен?
-
metton:
что метасимвол \'?\' здесь излишен?
лишний!
-
Может и лишний, но хуже от него не становится...
После доработки пришел к такому решению:
$text =~s /.*\\[s\\:\\s*(([1-2A-Za-zА-Яа-яё\\d]+)|([A-Za-zА-Яа-яё\\d]+[A-Za-zА-Яа-яё\\s\\d]+[A-Za-zА-Яа-яё\\d]+))\\s*\\](.*?)|(.*\\n?)/$1/gi;
Вот только меня группа [А-Яа-яё] смущает... никто не знает как она выглядит в HEX формате?
-
2Phoinix
Просто из любопытсва: а как у тебя с первоначальным выражением $text получился равным \'Some text 2\'?
PS: зря ты всё-таки не слушаешь совета (убрать \'?\'). Этот метасимвол здесь воообще ни на чо не влияет - так зачем лишний символ и лишняя работа парсеру?
-
metton
сложно сказать, но одно время работало... проверять не стал, т.к. перешел на второй вариант, но он тоже не подошел... т.к. в тексте может еще сущестовать символы ]
Мало того, я еще думаю в начале поставить ^ - что бы было понятно.
IMHO это не лишняя работа парсеру, а ограничивание вариантов для парсера
-
2Phoinix
Понимаешь, в данном контексте ((.*?)) метасимвол \'?\' ничего не ограничивает. Он означает ноль или один символ (предшествующий ему), а метасивол \'*\' означает ноль или более симолов. Следовательно, \'?\' не играет в данном контексте НИКАКОЙ РОЛИ!
-
metton
Приношу извинения... опечатался, не ? а $ - окончание строки....
P.S. Последний ремикс:
$text =~s /^.*\\[s\\:\\s*(([А-Яа-яё\\w]+)|([А-Яа-яё\\w]+[А-Яа-яё\\s\\w]+[А-Яа-яё\\w]+))\\s*\\].*\\[\\/s](.*$)|(.*\\n$)/$1/gi;
-
2Phoinix
Хочу извиниться - поторопился... Забавно, но, оказалось, что тот треклятый (:)) метасимвол \'?\' даже очень значим в шаблонах типа /.*?/. Читая "книгу с верблюдом" сегодня, обнаружил сей факт (причём где-то во введении). \'?\' в вышеуказанном шаблоне играет роль уменьшения жадности квантификаторов (в данном случае \'*\'). Т.е. шаблон ищет не самое длинное соответствие шаблону, а, наоборот, - самое короткое. И самое забавное - это то, что данный факт позволяет хорошо оптимизировать твой шаблон.
Т.е. для строки "Some text 1 [s: Some text 2] Some text 3 [/s] Some text 4", чтобы вытащить "Some text 2", используем такое:
$text =~ /.*?\\[s\\:\\s*(.*?)\\]/i;
А после, соответственно, находим "Some text 2" в $1.
Чтобы вытащить ещё что-то из этой строки, действуешь соответственно.
ОФФТОП:
2ALL
Я где-то читал, что локальные наборы символов по идее должны входить в класс \\w. А у меня почему-то не входят, а входит только в \'.\' От чего это зависит?
-
metton
Насколько я понял в класс \\w входят только латинские символы, цифры и _ , а с кириллицей возникает проблема, поэтому и приходится дополнительно задавать кириллические символы:
[а-яА-ЯёЁ\\w]
-
2Phoinix
Так есть точка, в которую входят и кириллические.
-
"." соответствует ЛЮБОМУ символу (исключя \\n, по умолчанию)
-
2Alone
Кто-то утверждает обратное?
-
упс :)
-
metton
Тогда вопрос? что ты понимаешь под локальным набором символов?
цитирую из любимой книги:
\\w - совпадает с символами, определяющими класс "слово" (алфавитно-цифровые плюс "_")
. - совпадение с любым символом, кроме конца строки (\\n)
-
man locale
-
Phoinix:
Насколько я понял в класс \\w входят только латинские символы, цифры и _
Не всегда, т.к. это зависит от реализации и настроек. Живой пример для Перл:
1)
print \'!\' if \'йцук\' =~ /\\w/;
2)
use locale;
print \'!\' if \'йцук\' =~ /\\w/;
дают разные результаты.
-
mike
Вот только я не пойму, что при use locale он делает с пробелами?
Он вырезает текст с пробелами, но при этом оставляет вместо текста один пробел, при наличии в тексте нескольких подряд пробелов он заменяет их, опять же, на один?
-
Пробелы они и африке пробелы(так же как табы и переводы строк) только черные. use locale влияет на выбор charmaps.
-
NeoNox:
Пробелы они и африке пробелы
Извините, но это не совсем так...
Например символ с ASCII кодом 160 (chr(160)) при кодировке cp1251 даст пробельный символ. И более того метасимвол \'\\s\' отловит этот символ как положенно. При других кодировках этого не происходит.
ps: Microsoft программы этот символ очень любят. (например Excel)
-
ondr:
Извините, но это не совсем так...
Читаем ман по регам:
\\s Пропуск. в системах, ограничивающихся поддержкаой ASCII, часто эквивалентно [ \\f\\n\\r\\t\\v], В системах с подержкой Юникода также часто включает управлящий символ "следующей строки" U+0085, а иногда свойство \\p{Z}
\\p{Z} — \\p{Separator} — символы, выполняющие функции разделителей, но не имеющие собственного визуального представления (разнообразные пробелы и т.д.)
\\p{Zs} — \\p{space separator} — различные типы пробелов (обычный пробел, наразрывный пробел, и пробелы фиксированной ширины)
Ман по РНР:
By default, a whitespace character is any character that the C library function isspace() recognizes, though it is possible to compile PCRE with alternative character type tables.
(Свободный перевод, извините за качество
По-умолчанию пробелом считается любой символ, который распознает библиотечная С-функция isspace(), хотя возможно скомпилировать PCRE с альтернативным набором символов)
На С не писал, не знаю. может кто просветит, какие символы распознает эта функция?
Оттуда же:
\\s any whitespace character
any переводится любой
-
metton:
/.*?/
Согласен. Ищет минимальное совпадение.
-
Yukko:
Оттуда же:
\\s any whitespace character
any переводится любой
Все правильно. Только речь не об этом. Читай внимательнее посты.
-
ondr:
Извините, но это не совсем так...
Можно и на ты.
Все правильно. Только речь не об этом. Читай внимательнее посты. ;)
-
NeoNox ondr
[OFF]Что-то тема раздулась и ушла не в ту степь....[/OFF]
В конце был поднят вопрос как прицепить к классу \\w кириллические символы, дабы не рисовать конструкцию - [а-яА-ЯёЁ\\w]. Когда я начал проверять это дело, то увидел что у меня теряются пробелы, которые мне тоже нужны, и соответственно задал насчет этого вопрос, но как сказал NeoNox:
Пробелы они и африке пробелы
И действительно, проблема выскочила из-за того, что результат обработки текста я выводил в браузер, а он по-определению не печатает просто так больше двух пробелов, я просто по-запарке про это забыл...
-
Так замени пробелы на
-
s/ {2}/ /g - лучше так, чередуя
-
Yukko ondr
Еще раз извиняюсь, за неправильно поставленный вопрос-ответ...
Мне нужно было вырезать текст для того, что бы его использовать в условии при запросе в базу данных, поэтому, количество пробелов мне важно... а в браузер я выводил, только проверку использования use locale, поэтому менять пробелы на &npsb; в данном случае мне не нужно...