Я ищу, чтобы удалить цитаты, сделанные с BBCode в PHP, как этот пример:
a sdasdsa dfv rdfgrgre gzdf vrdg
sdfsd fdsf dsf sdf[/quote]
the rest of the post text
Я смотрю на создание системы блокировки, поэтому пользователям не нужно видеть контент от тех, кого они не хотят. Так, скажем, «testuser» заблокирован, они не хотят, чтобы вся эта часть в кавычках, включая вторую вложенную цитату, была частью основной цитаты.
Таким образом, пост останется только с:
остальная часть текста поста
Мне интересно, как лучше это сделать. Я надеялся на регулярное выражение, но это сложнее, чем я думал, у меня есть такая попытка:
/\(.*)\[\/quote\]/is
Однако тогда он фиксирует все теги конечных кавычек.
Есть ли альтернативный метод, который быстро или хорошее решение для моего регулярного выражения?
Подводя итог: удалите первоначальную цитату из заблокированного пользователя и все, что находится внутри этой цитаты, но ничего больше вне ее.
Решение
Насколько я могу судить, это не простой процесс. Вот мои шаги …
- использование
preg_split()
разделить входную строку тремя способами: открывающие кавычки, закрывающие кавычки и другие. Я разделяю открывающие и закрывающие теги, но использую DELIM_CAPTURE
сохранить их в выходном массиве и в исходной позиции / порядке. NO_EMPTY
используется для того, чтобы в цикле foreach не было бесполезных итераций.
- Выполните цикл по сгенерированному массиву и найдите пропущенное имя пользователя.
- Когда цитата целевого пользователя найдена, сохраните начальный индекс этого элемента и установите
$open
до 1.
- Всякий раз, когда новый открывающий тег цитаты найден
$open
увеличивается
- Всякий раз, когда найден новый закрывающий тег цитаты
$open
уменьшается.
- Как только
$open
достигает 0
, $start
а также end
индексы подаются к range()
создать массив, заполненный числами между двумя точками.
array_flip()
, конечно, перемещает значения в клавиши.
array_diff_key()
удаляет диапазон точек из массива, сгенерированного preg_split()
,
- Если все пойдет гладко,
implode()
склеит подстроки вместе, сохранив только нужные компоненты.
Код: (демонстрация)
/*
This function DOES NOT validate the $bbcode string to contain a balanced number of opening & closing tags.
This funcion DOES check that there are enough closing tags to conclude a targeted opening tag.
*/
function omit_user_quotes($bbcode,$user){
$substrings=preg_split('~(\[/?quote[^]]*\])~',$bbcode,NULL,PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
$opens=0; // necessary declaration to avoid Notice when no quote tags in $bbcode string
foreach($substrings as $index=>$substring){
if(!isset($start) && $substring==""){ // found targeted user's first opening quote
$start=$index; // disqualify the first if statement and start searching for end tag
$opens=1; // $opens counts how many end tags are required to conclude quote block
}elseif(isset($start)){
if(strpos($substring,'[quote=')!==false){ // if a nested opening quote tag is found
++$opens; // increment and continue looking for closing quote tags
}elseif(strpos($substring,'
')!==false){ // if a closing quote tag is found
--$opens; // decrement and check for quote tag conclusion or error
if(!$opens){ // if $opens is zero ($opens can never be less than zero)
$substrings=array_diff_key($substrings,array_flip(range($start,$index))); // slice away unwanted elements from input array
unset($start); // re-qualify the first if statement to allow the process to repeat
}
}
}
}
if($opens){ // if $opens is positive
return 'Error due to opening/closing tag imbalance (too few end tags)';
}else{
return trim(implode($substrings)); // trims the whitespaces on either side of $bbcode string as feature
}
}
/* Single unwanted quote with nested innocent quote: */
/*$bbcode='
a sdasdsa dfv rdfgrgre gzdf vrdg
sdfsd fdsf dsf sdf[/quote]
the rest of the test'; */
/* output: the rest of the test */
/* Complex battery of unwanted, wanted, and nested quotes: */
$bbcode='Keep this
Don\'t keep this because
said don\'t do it
... like that\'s a good reason
It\'s tricky business, no?
[/quote][/quote]
[/quote]
Let\'s remove a second set of quotes
Another quote block
Let\'s do a third quote inside of my quote...
Another quote block
[/quote]
This should be good, but
What if quotes himself inside of his own quote[/quote]?';
/* output: Keep this
Let's remove a second set of quotes
Let's do a third quote inside of my quote...
This should be good, but
What if ? */
/* No quotes: */
//$bbcode='This has no bbcode quote tags in it.';
/* output: This has no bbcode quote tags in it. */
/* Too few end quote tags by innocent user:
(No flag is raised because the targeted user has not quoted any text) */
//$bbcode='This has not end tag.';
/* output: This has not end tag. */
/* Too few end quote tags by unwanted user: */
//$bbcode='This has not end tag.';
/* output: Error due to opening/closing tag imbalance (too few end tags) */
/* Too many end quote tags by unwanted user:
(No flag is raised because the function does not validate the bbcode text as fully balanced) */
//$bbcode='This has too many end tags.[/quote]';
/* output: This tags.[/quote] */
$user='testuser';
echo omit_user_quotes($bbcode,$user); // omit a single user's quote blocks
/* Or if you want to omit quote blocks from multiple users, you can use a loop:
$users=['mickmackusa','NaughtySquid'];
foreach($users as $user){
$bbcode=omit_user_quotes($bbcode,$user);
}
echo $bbcode;
*/
То, что вы хотите, не возможно с одним регулярным выражением. Я бы порекомендовал сканировать файл, пока не найдете
тег, с которым вы сталкиваетесь. Когда счетчик достигнет 0, измените логическое значение для фильтрации на false. тег, с которым вы сталкиваетесь после того, как логическое значение истинно. Уменьшить счетчик для каждого
Вот какой-то судокод. Возможно, вам придется изменить его в зависимости от вашего приложения, но я думаю, что он показывает общий алгоритм для использования.
filtering = false
counter = 0
for each line:
if line contains ""filtering = true
counter = 0
if line contains "[quote="counter += 1
if line contains "
counter -= 1
if counter = 0
filtering = false
if not filtering
print line