Как добавить ограничение в регулярное выражение - PullRequest
0 голосов
/ 16 апреля 2019

У меня есть функция Regex, которая позволяет мне заменить слово в тексте при появлении X. Я пытаюсь добавить условие, не заменяйте, если слово находится в теге <h1>,<h2>,<h3> и на изображении alt маяк,Может ли кто-нибудь помочь мне отредактировать функцию, чтобы добавить это условие, пожалуйста.

public function str_ireplace_n($search, $replace, $subject, $occurrence)
{
    $search = preg_quote($search);
    return preg_replace("/^((?:(?:.*?$search){" . --$occurrence . "}.*?))$search/i", "$1$replace", $subject);
}

Пример:

$text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. <h1>Lorem ipsum dolor sit</h1> Proin libero erat, malesuada eget volutpat vitae, efficitur vitae ipsum. Vivamus et <h2>Lorem ipsum dolor sit</h2> justo non quam laoreet euismod. Ut eget dapibus ligula. <img src="url" alt="Lorem ipsum dolor sit"/> Vestibulum vestibulum."

// I replace the second Lorem in this text by a link
$text = $this->str_ireplace_n('Lorem', ' <a href="' . $domain . '" alt="">Lorem</a> ', $text, 2); //2 for the second occurence

//The result will add a link on the Lorem inside the <h1> and I want to avoid this.
//I want the Regex do nothing in the case where the keyword is in h1 h2 or alt of image

Я не выбираю "Lorem", который хочу заменить, случайность случайна .Я должен убедиться, что я ничего не делаю, когда происходит <h1> / <h2> или изображение alt.

Заранее благодарен

1 Ответ

1 голос
/ 16 апреля 2019

Лично я бы сначала использовал что-то вроде preg_split:

$string = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. <h1>Lorem ipsum dolor sit</h1> Proin libero erat, malesuada eget volutpat vitae, efficitur vitae ipsum. Vivamus et <h2>Lorem ipsum dolor sit</h2> justo non quam laoreet euismod. Ut eget dapibus ligula. <img src="url" alt="Lorem ipsum dolor sit"/> Vestibulum vestibulum.';

$split = preg_split('/(<[^\/]+(?:\/|<\/[^>]+)>)/', $string, null, PREG_SPLIT_DELIM_CAPTURE);

Что дает вам это (это основная вещь, которую нам нужно сделать):

Array
(
    [0] => Lorem ipsum dolor sit amet, consectetur adipiscing elit. 
    [1] => <h1>Lorem ipsum dolor sit</h1>
    [2] =>  Proin libero erat, malesuada eget volutpat vitae, efficitur vitae ipsum. Vivamus et 
    [3] => <h2>Lorem ipsum dolor sit</h2>
    [4] =>  justo non quam laoreet euismod. Ut eget dapibus ligula. 
    [5] => <img src="url" alt="Lorem ipsum dolor sit"/>
    [6] =>  Vestibulum vestibulum.
)

Теперь мы разделили эти элементы внутри тегов. Так что теперь мы можем перебрать этот набор и проверить, является ли начальный символ < или нет, и иметь представление, находится ли он внутри или снаружи тега. Это должно работать до тех пор, пока ваши теги оканчиваются на </...> или />.

В основном HTML-теги + контент становятся разделителями, которые мы также фиксируем.

Дело в том, что обычный Regex не способен анализировать HTML, поскольку он не является обычным языком. Таким образом, мы должны сделать некоторую работу в PHP, чтобы связать все это вместе. Мы можем разбить его и упростить проблему с помощью простого регулярного выражения, как я сделал здесь.

$subject = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. <h1>Lorem ipsum dolor sit</h1> Proin libero erat, malesuada eget volutpat vitae, efficitur vitae ipsum. Vivamus et <h2>Lorem ipsum dolor sit</h2> Lorem justo non quam laoreet euismod. Ut eget dapibus ligula. <img src="url" alt="Lorem ipsum dolor sit"/> Vestibulum vestibulum.';

//word to replace
$search = 'Lorem';
//stuff to replace with
$replace = '<a href="Lorem">foo</a>';
 //what match to replace
$occurrence = 2;

function str_ireplace_n($search, $replace, $subject, $occurrence){
    $search = preg_quote($search);

    //separate the HTML from the "body" text
    $split = preg_split('/(<(?:h1|h2|h3|img)[^\/]+(?:\/|<\/[^>]+)>)/', $subject, null, PREG_SPLIT_DELIM_CAPTURE);
    //the number of current matches
    $match = 0;

    foreach($split as &$s){
        //if strpos < is 0 it's the first character - meaning its part of HTML (we don't want that)
        //if it matches search 
        if(0 !== strpos($s,'<') && preg_match('/\b'.$search.'\b/i', $s)){
            //increment the match counter
            ++$match;
             //replace the match if it's the nth one
            if($match == $occurrence)  $s = preg_replace('/\b'.$search.'\b/i',$replace,$s);
        }
    }

    return implode($split);
}

echo str_ireplace_n($search, $replace, $subject, $occurrence);

Выход:

Lorem ipsum dolor sit amet, consectetur adipiscing elit. <h1>Lorem ipsum dolor sit</h1> 
 Proin libero erat, malesuada eget volutpat vitae, efficitur vitae ipsum. Vivamus et 
  <h2>Lorem ipsum dolor sit</h2> <a href="Lorem">foo</a> justo non quam laoreet euismod. 
  Ut eget dapibus ligula. <img src="url" alt="Lorem ipsum dolor sit"/> Vestibulum vestibulum.

Это заменяемая часть <a href="Lorem">foo</a>

Я добавил несколько строковых возвратов для удобства чтения (в выходных данных) и еще один «Lorem» (во входных данных), так как за пределами HTML-тегов не было ни одного второго совпадения. В любом случае, если вы заметили, ничего внутри тегов HTML не было изменено. И в этом случае был изменен только второй матч.

Не совсем на 100% ясно, что вам нужно (как это часто бывает с вопросами такого типа), поэтому я пытаюсь объяснить, как это сделать, а не просто делать это.

Песочница

...