Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > PHP: Тексты > Регулярные выражения WIN->NIX


Автор: SamDark 20.11.2006, 11:05
Недавно написали с товарищем http://rmc.net.ru/article/programming/typograph/. Тестировался он на Windows (Denwer). При переносе на NIX-хост работать начал некорректно.

Чувствую, что дело в регулярных выражениях. Есть ли какие-либо особенности регулярок на WIN/NIX?

Автор: szz 20.11.2006, 11:09
Нету.

Автор: SamDark 20.11.2006, 12:17
Тогда есть ли идеи, почему по разному работает код на win/nix:

Код

<?/*
    при создании типографа помимо личного опыта использовались:
      http://philigon.ru/
      http://artlebedev.ru/kovodstvo/
      http://pvt.livejournal.com/
*/

// типографит html
function typo($str)
{
    $safe_blocks = array(
        "<pre[^>]*>" => "<\/pre>",
        "<style[^>]*>" => "<\/style>",
        "<script[^>]*>" => "<\/script>",
        "<!--" => "-->",
    );

    $pattern = "((?U)";
    foreach ($safe_blocks as $start => $end) $pattern .= "$start.*$end|";
    $pattern .= "<[^>]*[\s][^>]*>)";
    $str = preg_replace_callback("/$pattern/is", '_typo_stack', $str);

    $str = typo_text($str);
    $str = strtr($str, _typo_stack());
    return $str;
}


function _typo_stack($m = false)
{    
    static $arr = array();
    if ($m !== false)
    {
        $key = "<tag".count($arr).">";
        $arr[$key] = $m[0];
        return $key;
    }
    else
    {
        $t = $arr;
        unset($arr);
        return $t;
    }
}


// типографит текст.
function typo_text($str){
    if (trim($str) == "") return "";
      
    // то, что предположительно захочется переопределять
    $sym = array(
        "nbsp"    => "&nbsp;",
        "lnowrap" => '<span style="white-space:nowrap">',
        "rnowrap" => "</span>",

        "lquote"  => "&laquo;",
        "rquote"  => "&raquo;",
        "lquote2" => "&lsquo;",
        "rquote2" => "&rsquo;",

        "mdash"   => "&mdash;",
        "ndash"   => "&ndash;",
        "minus"   => "&minus;",

        "hellip"  => "&hellip;",
        "copy"    => "&copy;",
        "trade"   => "&trade;",
        "apos"    => "'",   // см. http://fishbowl.pastiche.org/2003/07/01/the_curse_of_apos
        "reg"     => "&reg;",
    );


    $html_tag = "(?:(?U)<.*>)";
    $hellip = "\.{2,4}";
    
    $phrase_end   = "(?:[)!?.]|$|\w)";
    $phrase_begin = "(?:$hellip|\w)";
    $any_quote    = "(?:$sym[lquote]|$sym[rquote]|$sym[lquote2]|$sym[lquote2])";
    
    $replace = array(

         // кавычки        
        "/(?<=\s|^)($html_tag*)(\")($html_tag*$phrase_begin$html_tag*)/"    => '$1'.$sym['lquote'].'$3',
        "/($html_tag*$phrase_end$html_tag*)(\")($html_tag*$phrase_end$html_tag*|\s|[,:])/"    => '$1'.$sym['rquote'].'$3',

        // Знак дефиса или два знака дефиса подряд - на знак длинного тире.
        // + Нельзя разрывать строку перед тире, например: Знание - сила, Курить - здоровью вредить.
        "/(\s+|^)(--?)(?=\s)/" => '$1'.$sym["mdash"],

        // Знак дефиса, ограниченный с обоих сторон цифрами - на знак короткого тире.
        "/(?<=\d)-(?=\d)/" => $sym["ndash"],

        // Нельзя оставлять в конце строки однобуквенные предлоги и союзы а, в, и, к, о, с, у.
        "/(?<=\s|^|\W)(а|в|к|о|с|у|я|о|об|не|за|на|как|без|что)(\s+)/i" => '$1'.$sym["nbsp"],
        
        // Нельзя отрывать частицы бы, ли, же от предшествующего слова, например: как бы, вряд ли, так же.
        "/(?<=\S)(\s+)(ж|бы|же|ли|либо|или)(?=$html_tag*[\s)!?.])/i" => $sym["nbsp"].'$2',
        
        // неразрывный пробел после инициалов
        "/((\s\w\.){1,3})(\s)(\w)/" => '$1'.$sym["nbsp"].'$4',

        // закавыченное внутри закавыченного
        //"/($sym[lquote].*)($sym[lquote])(.*)($sym[rquote])(.*$sym[rquote])/Us" => '$1'.$sym["lquote2"].'$3'.$sym["rquote2"].'$5',

        //
        //"/($sym[lquote]\S*)(\s+)(\S*$sym[rquote])/U" => '$1'.$sym["nbsp"].'$3',


        // два-четыре знака точки подряд - на знак многоточия (больше - мб авторской задумкой)
        "/$hellip/" => $sym["hellip"],
                                
        "/\(c\)/i"    =>    $sym["copy"],
        "/\(r\)/i"    =>    $sym["reg"],
        "/\(tm\)/i"    =>    $sym["trade"],
        "/'/"        =>    $sym["apos"],

/*

 - Нельзя разрывать строку перед дефисом или после дефиса. (Если разорвать строку 
   после дефиса, читатель может принять его за знак переноса.) Например, нельзя
   переносить: как-нибудь, генерал-майор, большая-пребольшая.

 - Нельзя разрывать строку после тире, если оно разделяет границы диапазона, например: 1799-1837, 10-15 кг.

 - Нельзя разрывать сокращённые словосочетания, например: и т.д., т.е., у.е.

 - Нельзя отрывать инициалы друг от друга и от фамилии, например: А.С. Пушкин, Дж.Вашингтон.

 - Нельзя отрывать имя собственное от относящегося к нему сокращения, например: гр. Иванов, пос. Молоково.

 - Нельзя отрывать число от относящейся к нему единицы измерения, например: 60 м2, 25 %. Нельзя отрывать 
   знаки номера (№) и параграфа () от относящегося к ним числа, например: № 5,  38.

 - Нельзя разрывать многоразрядные числа, например: 98 765 432.

 - Нельзя оставлять в конце строки служебные части речи (предлоги, союзы, частицы) из 
   двух или трёх букв, если они стоят в начале предложения.

*/

    );

    $str = preg_replace(array_keys($replace), array_values($replace), $str);
//    return $m[1].$str.$m[3];
    return $str;
}

Автор: smartov 20.11.2006, 14:25
SamDark, одинаковы ли версии php?

Автор: szz 20.11.2006, 14:51
Что там у нас в строке 69 произошло? 
  И почему именно на 69?  smile smile 

Автор: SamDark 20.11.2006, 17:15
smartov
4.4.2 = localhost
4.3.10 = на сервере

Некорректно работает именно на сервере... Где у нас ченджлог PHP?

szz
Описка при копировании. Поправил код в посте.

Автор: szz 21.11.2006, 04:08
Код

Где у нас ченджлог PHP?

http://www.php.net/ChangeLog-4.php
  Там стоко всего призошло...  копайся, мож найдешь.

Немного сомнительное место:
Код

        $t = $arr;
        unset($arr);
        return $t;


  Может в одном месте он как к копии относится, а в другом - как к ссылке? Т.е. unset посто удалит тот объект, на который ссылается $arr? И тогда плакала $t...
  Но так бы произошло в пятом, точно. А вот в таких минорных отличиях версий - хз...

Автор: SamDark 21.11.2006, 09:56
C unset() всё в норме. Проверил его комментированием.

В ченджлоге про PCRE только http://bugs.php.net/bug.php?id=33200

Если у кого есть хоть какой-то php-сервер, прошу оттестить данную строчку:
Цитата
Кибер-панк в рубрике Возрождение: рассказы "Сердце", "Эвакуация" и "Майский жук".


Если выдаёт ёлочки - работает как надо, если оставляет обычные кавычки - что-то здесь не так...

p.s. может magic мешает?

---

Попробовали на 4.3.2, хочтинг - те же результаты smile
4.0, Денвер - работает...

Автор: Mal Hack 21.11.2006, 10:30
Единственно где может быть глюк - в регистре...
Хотя никогда с таким не встречался...

Автор: SamDark 21.11.2006, 10:38
Mal Hack
Подробнее, пожалуйста.

Автор: -=Ustas=- 21.11.2006, 11:04
Скорее всего, по своему опыту именно с разнобоем в регах, проблема в locale. Нужно ставить нужную локаль для скрипта
Код

setlocale(LC_ALL, 'ru_RU.CP1251');

Если данная локаль на вашем серваке установлена, то должно помочь обязательно.

Автор: SamDark 21.11.2006, 11:54
Всем огромное спасибо!
Про локаль даже и не думал... а зря smile

Автор: -=Ustas=- 21.11.2006, 13:31
Цитата(SamDark @  21.11.2006,  11:54 Найти цитируемый пост)
Про локаль даже и не думал... а зря

В регах просто используются всякие классы и спец-символы, которые в разных кодировках по-разному кодируются.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)