Forum Webscript.Ru

Программирование => Регулярные выражения => Тема начата: Phoinix от 16 Августа 2003, 14:22:45

Название: Вырезка текста
Отправлено: 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;
Название: Вырезка текста
Отправлено: metton от 17 Августа 2003, 04:52:35
Не проверяя свои размышления и принимая во внимание время в которое я это пишу, могу сказать следующее:
имхо, из-за жадности квантификатовров при первом шаблоне $text будет иметь значение Some text 2] Some text 3 [/s]
Название: Вырезка текста
Отправлено: metton от 17 Августа 2003, 04:58:23
Извиняюсь, опечатался:
Some text 2] Some text 3 [/s
Название: Вырезка текста
Отправлено: Phoinix от 17 Августа 2003, 16:12:10
metton
Нет он возвращает правильное значение - Some text 2, но все-таки буду использовать второй вариант...

Просто интересно как возможно поведет себя регулярное выражение, на практике так как нужно, а в теории???
Название: Вырезка текста
Отправлено: metton от 24 Августа 2003, 02:27:35
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 совсем не то, что тебе нужно.

И ещё: (.*?)
Тебе не кажется, что метасимвол \'?\' здесь излишен?
Название: Вырезка текста
Отправлено: Yukko от 24 Августа 2003, 12:03:23
Цитировать
metton:
что метасимвол \'?\' здесь излишен?

лишний!
Название: Вырезка текста
Отправлено: Phoinix от 24 Августа 2003, 16:04:54
Может и лишний, но хуже от него не становится...
После доработки пришел к такому решению:

$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 формате?
Название: Вырезка текста
Отправлено: metton от 24 Августа 2003, 16:41:38
2Phoinix
Просто из любопытсва: а как у тебя с первоначальным выражением $text получился равным \'Some text 2\'?

PS: зря ты всё-таки не слушаешь совета (убрать \'?\'). Этот метасимвол здесь воообще ни на чо не влияет - так зачем лишний символ и лишняя работа парсеру?
Название: Вырезка текста
Отправлено: Phoinix от 24 Августа 2003, 17:18:11
metton
сложно сказать, но одно время работало... проверять не стал, т.к. перешел на второй вариант, но он тоже не подошел... т.к. в тексте может еще сущестовать символы ]

Мало того, я еще думаю в начале поставить ^ - что бы было понятно.
IMHO это не лишняя работа парсеру, а ограничивание вариантов для парсера
Название: Вырезка текста
Отправлено: metton от 24 Августа 2003, 21:50:36
2Phoinix
Понимаешь, в данном контексте ((.*?)) метасимвол \'?\' ничего не ограничивает. Он означает ноль или один символ (предшествующий ему), а метасивол \'*\' означает ноль или более симолов. Следовательно, \'?\' не играет в данном контексте НИКАКОЙ РОЛИ!
Название: Вырезка текста
Отправлено: Phoinix от 25 Августа 2003, 10:30:19
metton
Приношу извинения... опечатался, не ? а $ - окончание строки....

P.S. Последний ремикс:

$text =~s /^.*\\[s\\:\\s*(([А-Яа-яё\\w]+)|([А-Яа-яё\\w]+[А-Яа-яё\\s\\w]+[А-Яа-яё\\w]+))\\s*\\].*\\[\\/s](.*$)|(.*\\n$)/$1/gi;
Название: Вырезка текста
Отправлено: metton от 26 Августа 2003, 21:55:27
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. А у меня почему-то не входят, а входит только в \'.\' От чего это зависит?
Название: Вырезка текста
Отправлено: Phoinix от 27 Августа 2003, 10:16:56
metton
Насколько я понял в класс \\w входят только латинские символы, цифры и _ , а с кириллицей возникает проблема, поэтому и приходится дополнительно задавать кириллические символы:
[а-яА-ЯёЁ\\w]
Название: Вырезка текста
Отправлено: metton от 27 Августа 2003, 17:30:18
2Phoinix
Так есть точка, в которую входят и кириллические.
Название: Вырезка текста
Отправлено: Alone от 27 Августа 2003, 17:53:33
"." соответствует ЛЮБОМУ символу (исключя \\n, по умолчанию)
Название: Вырезка текста
Отправлено: metton от 27 Августа 2003, 23:26:28
2Alone
Кто-то утверждает обратное?
Название: Вырезка текста
Отправлено: Alone от 28 Августа 2003, 09:53:36
упс :)
Название: Вырезка текста
Отправлено: Phoinix от 29 Августа 2003, 12:42:50
metton
Тогда вопрос? что ты понимаешь под локальным набором символов?

цитирую из любимой книги:

\\w - совпадает с символами, определяющими класс "слово" (алфавитно-цифровые плюс "_")

. - совпадение с любым символом, кроме конца строки (\\n)
Название: Вырезка текста
Отправлено: NeoNox от 29 Августа 2003, 12:49:15
man locale
Название: Вырезка текста
Отправлено: mike от 29 Августа 2003, 12:52:47
Цитировать
Phoinix:
Насколько я понял в класс \\w входят только латинские символы, цифры и _

Не всегда, т.к. это зависит от реализации и настроек. Живой пример для Перл:

1)
print \'!\' if \'йцук\' =~ /\\w/;

2)
use locale;
print \'!\' if \'йцук\' =~ /\\w/;

дают разные результаты.
Название: Вырезка текста
Отправлено: Phoinix от 29 Августа 2003, 13:34:47
mike
Вот только я не пойму, что при use locale он делает с пробелами?

Он вырезает текст с пробелами, но при этом оставляет вместо текста один пробел, при наличии в тексте нескольких подряд пробелов он заменяет их, опять же, на один?
Название: Вырезка текста
Отправлено: NeoNox от 29 Августа 2003, 13:40:39
Пробелы они и африке пробелы(так же как табы и переводы строк) только черные. use locale влияет на выбор charmaps.
Название: Вырезка текста
Отправлено: ondr от 10 Сентября 2003, 14:18:46
Цитировать
NeoNox:
Пробелы они и африке пробелы


Извините, но это не совсем так...
Например символ с ASCII кодом 160 (chr(160)) при кодировке cp1251 даст пробельный символ. И более того метасимвол \'\\s\' отловит этот символ как положенно. При других кодировках этого не происходит.

ps: Microsoft программы этот символ очень любят. (например Excel)
Название: Вырезка текста
Отправлено: Yukko от 11 Сентября 2003, 13:45:57
Цитировать
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 переводится любой
Название: Вырезка текста
Отправлено: Yukko от 11 Сентября 2003, 13:47:40
Цитировать
metton:
/.*?/

Согласен. Ищет минимальное совпадение.
Название: Вырезка текста
Отправлено: ondr от 11 Сентября 2003, 13:58:56
Цитировать
Yukko:
Оттуда же:
\\s any whitespace character
any переводится любой


Все правильно. Только речь не об этом. Читай внимательнее посты.
Название: Вырезка текста
Отправлено: NeoNox от 11 Сентября 2003, 14:05:24
Цитировать
ondr:
Извините, но это не совсем так...

Можно и на ты.
Все правильно. Только речь не об этом. Читай внимательнее посты. ;)
Название: Вырезка текста
Отправлено: Phoinix от 11 Сентября 2003, 14:26:23
NeoNox ondr

[OFF]Что-то тема раздулась и ушла не в ту степь....[/OFF]

В конце был поднят вопрос как прицепить к классу \\w кириллические символы, дабы не рисовать конструкцию - [а-яА-ЯёЁ\\w]. Когда я начал проверять это дело, то увидел что у меня теряются пробелы, которые мне тоже нужны, и соответственно задал насчет этого вопрос, но как сказал NeoNox:
Цитировать
Пробелы они и африке пробелы

И действительно, проблема выскочила из-за того, что результат обработки текста я выводил в браузер, а он по-определению не печатает просто так больше двух пробелов, я просто по-запарке про это забыл...
Название: Вырезка текста
Отправлено: Yukko от 11 Сентября 2003, 14:32:25
Так замени пробелы на  
Название: Вырезка текста
Отправлено: ondr от 11 Сентября 2003, 14:42:59
s/ {2}/  /g - лучше так, чередуя
Название: Вырезка текста
Отправлено: Phoinix от 11 Сентября 2003, 15:08:15
Yukko ondr

Еще раз извиняюсь, за неправильно поставленный вопрос-ответ...
Мне нужно было вырезать текст для того, что бы его использовать в условии при запросе в базу данных, поэтому, количество пробелов мне важно... а в браузер я выводил, только проверку использования use locale, поэтому менять пробелы на &npsb; в данном случае мне не нужно...