Xpoint
   [напомнить пароль]

Автоматическая замена (str_replace/strtr)

Метки: [без меток]
2008-09-27 17:53:28 [обр] Василий[досье]

Необходимо чистить на лету код страниц, пытаюсь воспользоваться функциями str_replace/strtr,
нижеуказанный код замечательно удаляет все вхождения слова "ТЕСТ" но упорно не хочет
подавлять тэговые последовательности:(( Т.е. <p><b> </b></p>, <p> </p>, <span> </span> остаются в коде:(
В чем может быть дело?

$trans = array("<p><b> </b></p>", "<p> </p>", "<span> </span>",  "<p><span> </span></p>", "<p><strong> </strong></p>", "ТЕСТ");
$arProperty["DISPLAY_VALUE"] = str_replace($trans, "", $arProperty["DISPLAY_VALUE"]);
echo $arProperty["DISPLAY_VALUE"];?>

(с strtr ситуация ровно такая-же)

спустя 1 час 55 минут [обр] Алексей Шоков(6/9)[досье]
Немного не по теме — Tidy?
спустя 49 минут [обр] Михаил Кюршин aka ya-ya(69/414)[досье]
спустя 6 часов [обр] Ali(5/5)[досье]

А ты уверен что у тебя встречается именно такая последовательность?
Т.е. к примеру, между <p><b> и </b></p> стоит именно один пробел? Дело может быть в кодировках. Если строка в UTF-8, то пробелы бывают разные и кодируются по-разному, просты строковые функции могут не работать.
Советую использовать preg_replace с модификатором 'u'.

Ну и конечно, если стоит задача просто убрать теги, то использовать проще strip_tags (возможно со списком тех тегов, которые не надо убирать).

спустя 5 часов [обр] Василий[досье]
Ali[досье]А как можно посмотреть строку "живьем"? т.е. если я смотрю код страницы через админку в режиме просмотра исходного кода (эти странички хранятся в БД), то они содержат непосредственно "<p> </p>". phpmyadmin говорит, что кодировка в БД win 1251. А strip_tags мне вряд ли сгодится, я же не хочу убирать все параграфы, мне нужно выкинуть только оставшиеся после, встроенного в Битриксовский редактор чистильщика импорта из ворда, пустые параграфы, иногда с дополнительным форматированием пробела:)
спустя 1 час 56 минут [обр] Василий[досье]
Алексей Шоков[досье] очень даже по теме! спасибо! буду разбираться, возможно ли там настроить чистку не удаляя "легальные", предопределенные классы. и согласится ли хостер поставить адд-он:)
спустя 46 минут [обр] Василий[досье]

попробовал в качестве замены воспользоваться регулярными выражениями

$search = array ("/программа[\s]семинара:/i", 
"<p>[\s]</p>/i", 
"<p><b>[\s]</b></p>/i");
//что меняем
$replace = array ("", 
"", 
"");
//на что меняем
echo preg_replace($search, $replace, $arProperty["DISPLAY_VALUE"]);

"программа семинара" убивается без проблем, а злополучное "<p><b> </b></p>" перед каждым заголовком остается:(

ради интереса прогнал

echo strip_tags($arProperty["DISPLAY_VALUE"]);

работает. всё в кучу:)

Есть идеи?

спустя 1 час 23 минуты [обр] Василий[досье]
Попробовал заменить все пробелы (" ") на &nbsp;, действительно, символ между <p><b> </b></p> не входит в понятие " ". Можно как-то понять, что там, например заменить все символы на ASCII код?
спустя 51 минуту [обр] Илья Cтpeльцын aka SelenIT(24/171)[досье]
Можно регулярками (PCRE) воспользоваться, там есть \s для всего "пробелоподобного" (табуляции, все виды переводов каретки и т.п.)...
спустя 18 минут [обр] Василий[досье]
А это разве не то я пробовал? (см.выше)
$search = array ("/программа[\s]семинара:/i", 
"<p>[\s]</p>/i", 
"<p><b>[\s]</b></p>/i");
//что меняем
$replace = array ("", 
"", 
"");
//на что меняем
echo preg_replace($search, $replace, $arProperty["DISPLAY_VALUE"]);
спустя 26 минут [обр] Ali(5/5)[досье]

Василий[досье]Чтоб посмотреть живьем надо взять нужный кусок и вывести посимвольно (через ord()).
К стати обычно ставят не

[\s]

а

\s+?

И еще, добавь на всякий случай модификатор 'u' к регулярке. Или попробуй добавь для нахождения пробела и символ табуляции:

[\s\t]+?
спустя 6 часов [обр] Илья Cтpeльцын aka SelenIT(24/171)[досье]

Василий[досье], а открывающий ограничитель в том примере где? Я, честно говоря, при первом беглом взгляде даже не понял, что это регулярки. Должно было быть что-то вроде /<p>\s+?<\/p>/i (или с другим ограничителем, например, ~<p>\s+?</p>~i — чтобы не путаться с экранированием слешей в закрывающих тегах).

Ali[досье]

[\s\t]+?

Насколько мне известно, в этом смысла нет — табуляция уже включена в класс \s. А вот совет насчет ограничения жадности (\s+?) очень даже к месту!

спустя 13 часов [обр] Василий[досье]

Вот такой симбиоз на базе полученных советов имеет право на жизнь?

$search = array ("~<p>\s\t+?</p>~i", 
"~<p><b>\s\t+?</b></p>~i");
//что меняем
$replace = array ("", 
"");
//на что меняем
echo preg_replace($search, $replace, $arProperty["DISPLAY_VALUE"]);

В результате опять вижу:

<p><b> </b></p>

<p><b>2. Инженерная и специально-техническая защита кредитной организации.</b></p>

<p><b> </b></p>

<p><b>3. Требования безопасности при проектировании и строительстве объектов.</b></p>

<p><b> </b></p>

<p><b>4. Контроль состояния и техническая защита объекта: современные средства технической защиты.</b></p>

<p><b> </b></p>
спустя 1 час 54 минуты [обр] Ali(5/5)[досье]

Неправильно, ты почитай больше про символьные классы. Я тоже не учел что \t включается в пробельный класс.
Итого в твоём случае код выглядит либо так

$search = array ("~<p>\s+?</p>~i", 
"~<p><b>\s+?</b></p>~i");
//что меняем
$replace = array ("", 
"");
//на что меняем
echo preg_replace($search, $replace, $arProperty["DISPLAY_VALUE"]);

либо можно попробовать так (с модификатором для UTF-8)

$search = array ("~<p>\s+?</p>~iu", 
"~<p><b>\s+?</b></p>~iu");
//что меняем
$replace = array ("", 
"");
//на что меняем
echo preg_replace($search, $replace, $arProperty["DISPLAY_VALUE"]);

А лучше все-таки узнай, что у тебя за символ стоит в качестве пробела, например (для упрощения я предположил, что пустых символов не больше 5, чтоб отбросить длинные строки, можно еще попытаться поставить вместо .{1,5} несловарный класс \W+?, но я не уверен):

preg_match_all("~<p><b>.{1,5}</b></p>~si", $arProperty["DISPLAY_VALUE"], $match);
var_dump($match);
foreach ($match[0] as $m) {
$arr = array();
    for ($i=0;$i<strlen($m);$i++) $arr[$i] = "$m[$i] => ". ord($m[$i]);
var_dump($arr);    
}

В результате получатся массивы, содержащие соответствие символа и ASCII кода для найденных строк. Код пробела 32, что у тебя там стоит - узнаешь...

спустя 8 минут [обр] Алексей Севрюков(162/1280)[досье]
Там может стоять неразрывный пробел, в \s он не входит. Его ASCII код - 160.
спустя 23 минуты [обр] Василий[досье]
Алексей Севрюков[досье] Вы правы! именно 160! <<<array(15) { [0]=> string(7) "< => 60" [1]=> string(8) "p => 112" [2]=> string(7) "> => 62" [3]=> string(7) "< => 60" [4]=> string(7) "b => 98" [5]=> string(7) "> => 62" [6]=> string(8) " => 160" [7]=> string(7) "< => 60" [8]=> string(7) "/ => 47" [9]=> string(7) "b => 98" [10]=> string(7) "> => 62" [11]=> string(7) "< => 60" [12]=> string(7) "/ => 47" [13]=> string(8) "p => 112" [14]=> string(7) "> => 62" }>>>
Нашел только на каком-то .UA сайте, что это nbsp, сейчас полезу в талмуд по PHP, с чем его едят:)
Ali[досье] - с меня низкий поклон и +3!
спустя 1 час 37 минут [обр] Василий[досье]
даже стыдно спрашивать, но что-то не получается, пробовал и <<<
"~<p><b>&(nbsp|#160);</b></p>~i">>> и <<<"~<p><b>chr(160)</b></p>~i">>> и нет прогресса :(
 PCRE проштудировал, не нашел.
спустя 58 секунд [обр] Ali(5/5)[досье]

Ок, рад что помог.
Вот что я нашел в инете насчет пробелов.

Unicode defines 18 different spaces, such as n- and m-sized spaces, and a non-breaking space.
// Remove space characters
$text = preg_replace( '/\p{Zs}/u', ' ', $text );
Это решение для UTF и всех пробелов.

Если же у вас кроме такого пробела не бывает других, можно просто добавить неразрывный пробел в символьный класс для замены, т.е. $search = array("~<p>[\s\xA0]+?</p>~i", "~<p><b>[\s\xA0]+?</b></p>~i");, хотя мне больше нравится универсальный вариант...

спустя 53 минуты [обр] Василий[досье]
Ali[досье] Спасибо, наконец получилось. Универсальные решения всегда практичнее уникальных, но не замедлит ли работу дополнительное "прочесывание" при замене всех пробелов? Вообще, отвлекаясь от темы, на сколько высока нагрузка на сервер? У меня есть еще редко но назойливо встречающиеся последовательности и я их правлю за пользователями непосредственно в импортированных текстах. Целесообразно ли и их для облегчения жизни добавить в список?
спустя 34 минуты [обр] Ali(5/5)[досье]
Если правка один раз, то особо не скажется на сервере, если обработка на каждом выводе, то тут чем меньше тем лучше...
В принципе добавление еще нескольких вариантов замены сильно не меняет скорости. Есть мнение, что одно более сложное регулярное выражение выполняется быстрее, чем несколько простых (делается всего проход по тексту, возможны оптимизации компилятора и проч.), поэтому я думаю, что лучше составить одно выражение для замены (конечно, если заменяется одинаково).
Например ~<p>(?:\p{Zs}+?|<b>\p{Zs}+?</b>)</p>~i
спустя 35 минут [обр] Василий[досье]
Ali[досье]Да, при каждом вызове:( Т.е. оптимальным решением является внедрение в модуль битрикса на стадии добавления статьи... а служебные модули обновляются при обновлении системы.. ну это уже мысли вслух:)
Powered by POEM™ Engine Copyright © 2002-2005