Замена вложенных двойных кавычек в строке

Итак, я типографский нацист (они похожи на граммар-наци на стероидах), и у меня есть строка, которая может содержать многоуровневые двойные кавычки, например:

$str = 'Outer text "first level "second level "third level" second level" first level" outer text';

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

  • 1-й уровень: текст („ и ”)
  • 2-й уровень: текст (» и «)
  • 3-й уровень: текст (’)
  • любые дополнительные уровни: текст (’)

Таким образом, приведенный выше текст будет выводиться как:

Внешний текст первый уровень второй уровень третий уровень второй уровень первый уровень внешний текст

Кроме того, возможно, что в строке есть одноуровневые пары "":

$str = 'Quote from my book: "She didn\'t feel "depressed", "tired" or "sad"."';

Таким образом, это будет выводиться как:

Цитата из моей книги: Она не чувствовала себя подавленной, усталой или грустной.

(Это может быть сложно, но мы знаем, что за " всегда следует или предшествует пробел , or punctuation ,, ., ;, ?, !)

Наконец, $str может также содержать HTML, где кавычки атрибутов не следует менять:

$str = '<p class="quote">The error said: <span class="error_msg">"Please restart your "fancy" computer!"</span></p>';

Я слышал, что использование рекурсивного регулярного выражения было бы возможным решением, но я ищу более эффективный способ, потому что строки могут быть длинными HTML-текстами.

ОБНОВЛЕНИЕ. Кажется, я пропустил свойство CSS quotes и элемент <q>. Это делает встроенные кавычки более элегантными.


person gpap    schedule 08.04.2013    source источник
comment
На самом деле я не могу придумать какой-либо волшебной или простой функции для этого. Не бойтесь регулярного выражения, чувак, оно в среднем на 300% медленнее, чем простая функция замены строки, но чтобы действительно заметить это, вам нужно запустить его снова ОГРОМНЫЕ тексты....   -  person aleation    schedule 08.04.2013
comment
offtop: Почему вы используете «указывающую вправо двойную кавычку» слева и «справа»?   -  person sectus    schedule 08.04.2013
comment
@sectus: в венгерской типографике это правильный символ для использования при цитировании в кавычках: en.wikipedia.org/wiki/   -  person gpap    schedule 08.04.2013
comment
Я не думаю, что два типа вашего ввода можно отличить друг от друга, например: "b" m "c" может быть „b” m „c” или также может быть „b» m «c”. Достаточно ли одного пробела, чтобы определить, является ли " конечным знаком или нет (я думаю, что что-то вроде /\w"/ является конечным маркером, /\s"/ - начальным маркером)?   -  person complex857    schedule 08.04.2013


Ответы (2)


попробуйте это "#\"(([^()]+|(?R))*)\"#" является рекурсивным регулярным выражением

образец

class Replace1{
   public $Out,$Depth=0;
   function __construct($Query){
        $this->Depth=0;
        $this->Out=$this->Reaplce($Query);  
   }
   function Reaplce($Query){
      //echo "**********".$Query.$this->Depth."\n";
       $Query = preg_replace_callback("#\"(([^()]+|(?R))*)\"#",function($m){
             $this->Depth++;
             $R=$this->Reaplce($m[1]);
             $this->Depth--;
            return $R;
        },$Query);  
        switch($this->Depth){
          case 0:
             return $Query;
          case 1:
             return '&bdquo;'.$Query.'&rdquo;';
          case 2:
             return '&raquo;'.$Query.'&laquo;'; 
          case 3:
             return '&rsquo;'.$Query.'&rsquo;';  
          default:
             return '&rsquo;'.$Query.'&rsquo;';                     
        }
        return $Query;

  }


}
$obj=new Replace1('Outer text "first level "second level "third level" second level" first level" outer text');
echo $obj->Out;

старый php

function R($m){
        Replace1::$Depth++;
        $R=Replace1::Reaplce($m[1]);
        Replace1::$Depth--;
        //echo "***".$R.$this->Depth."\n";
        return $R;
}
class Replace1{
public static $Out,$Depth=0;

    function __construct($Query){
    self::$Depth=0;
    self::$Out=self::Reaplce($Query);   
}

static function Reaplce($Query){
    //echo "**********".$Query.$this->Depth."\n";

    $Query = preg_replace_callback("#\"(([^()]+|(?R))*)\"#","R",$Query);
    //echo "**********".$Query.$this->Depth."\n";   
    switch(self::$Depth){
        case 0:
           return $Query;
        case 1:
           return '&bdquo;'.$Query.'&rdquo;';
        case 2:
           return '&raquo;'.$Query.'&laquo;'; 
        case 3:
           return '&rsquo;'.$Query.'&rsquo;';  
        default:
           return '&rsquo;'.$Query.'&rsquo;';         


    }
    return $Query;

}


}
$obj=new Replace1('Outer text "first level "second level "third level" second level" first level" outer text');
echo Replace1::$Out;

выход

Outer text „first level »second level ’third level’ second level« first level” outer text

HTML-просмотр

Outer text &bdquo;first level &raquo;second level &rsquo;third level&rsquo; second level&laquo; first level&rdquo; outer text

если удалить эхо-комментарий //, вывод будет

 **********Outer text "first level "second level "third level" second level" first level" outer text0
 **********first level "second level "third level" second level" first level1
 **********second level "third level" second level2
 **********third level3
 Outer text &bdquo;first level &raquo;second level &rsquo;third level&rsquo; second level&laquo; first level&rdquo; outer text
person mohammad mohsenipur    schedule 08.04.2013
comment
выдает ошибку: E_ERROR: type 1 -- Использование $this, когда не в контексте объекта -- в строке 11 phpfiddle.org/main/code/v0p-xsq - person razz; 08.04.2013
comment
ваша версия php старше 5.3.3. нет проблем, я тоже добавляю код для старого php - person mohammad mohsenipur; 08.04.2013
comment
да, теперь это работает :) только для первого типа строк! - person razz; 08.04.2013

Разбор HTML для такого умного цитирования если не невозможен, то очень сложная задача.

У меня есть сборка JoliTypo, которая использует загрузчик DOM (\DomDocument) и обрабатывает все текстовые строки, чтобы применить некоторую типографику. исправьте это: EnglishQuotes — один из них, но на данный момент он обрабатывает только первый уровень. Во французском языке у нас также есть другая иерархия цитат, так что это определенно в моем списке дел.

Хотя решение @mohammad работает для простых строк, в сочетании с JoliTypo у вас может быть шанс получить то, что вы хотите, надежным способом для больших документов HTML.

Могу я спросить, в какой локали используется такое цитирование (Outer text „first level »second level ’third level’ second level« first level” outer text)?

person Damien    schedule 04.09.2013
comment
Правила цитирования предназначены для венгерского языка. - person complex857; 04.09.2013