preg_replace_callback: включая фигурные скобки в шаблоне: {захватывается, } нет

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

Функция пытается также включить символы ', { и } как "алфавитные"

function String_SplitSentence($string)
{
 $res = array();

 preg_replace_callback("~\b(?<han>\p{Han}+)\b|\b(?<alpha>[a-zA-Z0-9{}']+)\b|(?<other>[^\p{Han}A-Za-z0-9\s]+)~su",
 function($m) use (&$res) 
 {
 if (!empty($m["han"])) 
 {
  $t = array("type" => "han", "text" => $m["han"]);
  array_push($res,$t);
 }
 else if (!empty($m["alpha"])) 
 {
  $t = array("type" => "alpha", "text" => $m["alpha"]);
  array_push($res, $t);
 }
 else  if (!empty($m["other"])) 
 {
  $t = array("type" => "other", "text" => $m["other"]);
  array_push($res, $t);
 }
 },
 $string);

 return $res;
}

Однако что-то не так с фигурными скобками.

print_r(String_SplitSentence("Many cats{1}, several rats{2}"));

Как видно из выходных данных, функция обрабатывает {как буквенный символ, как указано, но останавливается на}, и вместо этого обрабатывает его как "другой".

Array
(
    [0] => Array
        (
            [type] => alpha
            [text] => Many
        )

    [1] => Array
        (
            [type] => alpha
            [text] => cats{1
        )

    [2] => Array
        (
            [type] => other
            [text] => },
        )

    [3] => Array
        (
            [type] => alpha
            [text] => several
        )

    [4] => Array
        (
            [type] => alpha
            [text] => rats{2
        )

    [5] => Array
        (
            [type] => other
            [text] => }
        )

Что я делаю неправильно?

1 ответ

Решение

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

~(?<han>\p{Han}+)|(?<alpha>[a-z\d{}']+)|(?<other>\S+)~ui

Беда с \b это то, что он ищет \w персонажи. \w представляет заглавные буквы, строчные буквы, цифры и подчеркивания. Ссылка: /questions/47145192/raznitsa-mezhdu-w-i-b-metasimvolami-regulyarnyih-vyirazhenij/47145249#47145249

Также ваш шаблон не включает в себя .с, чтобы вы могли удалить s Модификатор


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

function String_SplitSentence($string){
    if(!preg_match_all("~(?<han>\p{Han}+)|(?<alpha>[a-z\d{}']+)|(?<other>\S+)~ui",$string,$out)){
        return [];  // or $string or false
    }else{
        foreach($out as $group_key=>$group){
            if(!is_numeric($group_key)){  // disregard the indexed groups (which are unavoidably generated)
                foreach($group as $i=>$v){
                    if(strlen($v)){  // only store the value in the subarray that has a string length
                        $res[$i]=['type'=>$group_key,'text'=>$v];
                    }
                }
            }
        }
        ksort($res);
        return $res;
    }
}

Демонстрация о вашем шаблоне: https://regex101.com/r/6EUaSM/1

\ b после того, как ваш класс персонажей запутался. } не входит в \w учебный класс. Regex хочет сделать хорошую работу для вас - он захватил "жадно", пока не может больше. } из-за границы слова.

Другие вопросы по тегам