Jump to content
  • 0

Проблема с регулярным выражением


rash
 Share

Question

Вот только что взялся за PHP, и сразу застрял на простейшей задаче (на мой взгляд).

Надо найти в тексте и определённым образом обработать все одно- и двухбуквенные слова. Для этого я составил регулярное выражение и использовал сфункцию preg_replace:

$textdata = preg_replace("/\s([а-Яё]{1,2})\s/", " *\\1* ", $textdata);

При этом результат обработки получается примерно таким:

Примочка монотонно представляет собой лирический фузз, *и* здесь мы видим ту самую каноническую секвенцию с разнонаправленным шагом отдельных звеньев. Явление культурологического порядка дает неизменный фьюжн, благодаря употреблению микромотивов (нередко из одного звука, *а* также двух-трех с паузами). Интервально-прогрессийная континуальная форма mezzo forte выстраивает дисторшн, *в* таких условиях можно спокойно выпускать пластинки раз *в* три года. Детройтское техно регрессийно начинает композиционный эффект "вау-вау", однако сами песни забываются очень быстро. Субтехника иллюстрирует флюгель-горн, благодаря быстрой смене тембров (каждый инструмент играет минимум звуков). Тетрахорд имитирует музыкальный канал, *и* если *в* одних голосах или пластах музыкальной ткани сочинения еще продолжаются конструктивно-композиционные процессы предыдущей части, то *в* других - происходит становление новых.

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

Link to comment
Share on other sites

25 answers to this question

Recommended Posts

  • 0
Вот только что взялся за PHP, и сразу застрял на простейшей задаче (на мой взгляд).

Надо найти в тексте и определённым образом обработать все одно- и двухбуквенные слова. Для этого я составил регулярное выражение и использовал сфункцию preg_replace:

$textdata = preg_replace("/\s([а-Яё]{1,2})\s/", " *\\1* ", $textdata);

При этом результат обработки получается примерно таким:

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

Регулярка правильная.

Link to comment
Share on other sites

  • 0

Может полный код поможет понять в чем дело? Уже попробовал несколько других вариантов — пока безрезультатно…

Это только черновик:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Результаты обработки</title>
<style type="text/css">
body {
font: small Verdana, Geneva, Arial, Helvetica, sans-serif;
}
#result {
border: 1px dotted #99F;
padding: 10px;
margin: 10px;
}
</style>
</head>
<body>
<h1>Получены данные:</h1>
<?
$textdata = htmlspecialchars($_POST["text"]);
$textdata = stripslashes($textdata);
$textdata = preg_replace("/\s([а-Яё]{1,2})\s/", " *\\1* ", $textdata);
echo "<div id=\"result\">".$textdata."</div>";
?>
</body>
</html>

Link to comment
Share on other sites

  • 0
Может полный код поможет понять в чем дело? Уже попробовал несколько других вариантов — пока безрезультатно…

Это только черновик:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Результаты обработки</title>
<style type="text/css">
body {
font: small Verdana, Geneva, Arial, Helvetica, sans-serif;
}
#result {
border: 1px dotted #99F;
padding: 10px;
margin: 10px;
}
</style>
</head>
<body>
<h1>Получены данные:</h1>
<?
$textdata = htmlspecialchars($_POST["text"]);
$textdata = stripslashes($textdata);
$textdata = preg_replace("/\s([а-Яё]{1,2})\s/", " *\\1* ", $textdata);
echo "<div id=\"result\">".$textdata."</div>";
?>
</body>
</html>

Мне точно полный код не поможет - я ПХП не знаю...

Link to comment
Share on other sites

  • 0

Понял, пробовал, стало еще хуже…

По� *�* итическое м� *�* нипу� *�* иров� *�* ние, осо� *�* енно *в* ус� *�* овиях по� *�* итической нест *а* *б* и� *�* ьност *и* , ст *а* *б* и� *�* ьно. Приним� *�* *я* во вним� *�* ние по� *�* ицию *�* �. *Ф* укуямы, понятие по� *�* итического уч *а* стия *�* �еоретически и� *��* *�* юстрирует доиндустри� *��* *�* ьны *�* � *�* �ип по� *�* итической ку� *�* ьтуры, *�* � *�* � *о* мо� *�* ет привест *и* *к* военно-по� *�* итической *и* идео� *�* огической конфронт *а* *�* �ии *с* Японией. Соци� *��* *�* ьно-экономическое р� *��* *�* витие приводит постиндустри� *��* *�* и� *�* *м* , утвер� *�* д� *�* ет руководите� *�* ь *а* пп� *�* р� *��* � *�* � Пр� *�* вите� *�* ьства. По� *�* итическ� *�* *я* система верифицирует конструктивны *�* � *�* �еномен *�* �о� *�* пы, *�* � *�* � *о* по� *�* учи� *�* *о* отр� *��* *�* ение *в* *�* �руд� *��* � Михе� *�* ьса.
Link to comment
Share on other sites

  • 0

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

А насчет кодировки сейчас попробую, но хотелось бы работать с UTF все-таки.

Плохо дело, проблема действительно в кодировках, с CP1251 вроде пока проблем не вижу, осталось найти, как заставить это все работать с UTF :-)

Link to comment
Share on other sites

  • 0

Они у меня и так все в UTF, странно, с несколькими выражениями до этого проблем не было, а с некоторыми вот такая чушь происходит…

Кстати, может кто намекнуть, как в строке найти, к примеру, вложенные скобки любого уровня, чтобы была возможность их заменить на другие. Новую тему создавать не хочется, и пока застрял… :-)

Link to comment
Share on other sites

  • 0
Они у меня и так все в UTF, странно, с несколькими выражениями до этого проблем не было, а с некоторыми вот такая чушь происходит…

Кстати, может кто намекнуть, как в строке найти, к примеру, вложенные скобки любого уровня, чтобы была возможность их заменить на другие. Новую тему создавать не хочется, и пока застрял… :-)

http://www.pcre.ru/eval/

создавай регулярки на лету...

Link to comment
Share on other sites

  • 0

Прочитал внимательно тему...

rash, в твоём случае регулярное выражение должно быть примерно таким: /\s([Ё-я]{2,4})\s/i

Не забывай, что для кодирования одного символа кириллицы в utf-8 используется два байта, а не один как в cp1251.

Link to comment
Share on other sites

  • 0

Я понимаю то, что кириллица кодируется двумя байтами, но не совсем понимаю, что надо сделать, чтобы при этом нормально функционировали регулярные выражения (к сожалению, еще слишком мало знаю), ведь у меня все файлы и так находятся в UTF, таким образом расхождений в кодировании быть не должно.

Кстати, когда я экспериментировал, решая проблему самостоятельно, я пробовал даже перечислить весь алфавит явно, но в UTF все равно ничего как следует не работало.

Link to comment
Share on other sites

  • 0

Ок. Вот твоё выражение из первого поста: /\s([а-Яё]{1,2})\s/

Что происходит? Сначала ты ищешь в одном байте (литера "1" в фигурных скобках) совпадение с двумя байтами символа из набора в квадратных скобках и, конечно же, совпадений не находишь, поскольку два байта не равно одному. Далее всё то же самое, но уже в двух байтах (литера "2" в фигурных скобках), соответственно совпадения вполне возможны, что мы и видим в результате из твоего первого поста в этой теме.

Путём нехитрых умозаключений можно понять, что нас интересует не один и два байта, а два и четыре, что я и предложил постом выше: /\s([Ё-я]{2,4})\s/i.

Link to comment
Share on other sites

  • 0

Хм, то есть при анализе регулярного выражения формально символом считается один байт, независимо от реально используемой кодировки?

Проверю это предположение завтра, сегодня уже поздно, и если это окажется действительно так — буду очень благодарен, потому что станет понятно, как не допустить ошибок в следующий раз. Впрочем, все равно спасибо за попытки помочь и терпение, независимо от результата :-)

Link to comment
Share on other sites

  • 0

Да, похоже что дело именно в этом, еще не все работает идеально, но уже нет таких ужасных искажений текста.

Кстати, ведь задавая квантификатор {2,4} мы будем осуществлять поиск по 2, 3 и 4 байтам, и хотя на тестовых примерах этого заметно не было, не может ли поиск по трем байтам дать какой-либо «побочный эффект», не имеет ли смысл переформулировать это так:

/\s([Ё-я]{2}|[Ё-я]{4})\s/

Link to comment
Share on other sites

  • 0

Побочных эффектов не будет, поскольку три не равно ни двум, ни четырём, а мы ищем только кириллицу. Два байта символа кириллицы не равны двум символам латиницы или символу другого языка.

А вот какой вариант будет работать быстрее даже не знаю. Я бы потестил и просто выбрал самый быстрый. :)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. See more about our Guidelines and Privacy Policy