Cómo envolver secuencias de palabras o palabras que no han sido ya envueltos?
-
29-09-2019 - |
Pregunta
Estoy tratando de envolver palabras y secuencia de palabras de una lista dada con preg_replace. Casi funciona, pero hay algunos casos de uso no y no puedo calcularlo cómo.
Por ejemplo, yo hago esto:
// sort by descending length
usort($this->_keywords, function($a,$b){return(strlen($a)<strlen($b));});
// wrapper is -%string%-
foreach ($this->_keywords as $keyword) {
$value = preg_replace('/((?!-)' . $keyword . '(?!-))/i', str_replace('%string%', '\1', $this->_wrapper), $value);
}
A partir de esta lista de palabras clave:
- lorem
- ipsum
- sit amet
- nula
- sed
- sed enim
Me gustaría dar lugar a:
-Lorem - -ipsum - dolor -Siéntate amet - , consectetur adipiscing elit. Phasellus rhoncus venenatis Orci SED porta. sed sin dolor eros. Suspendisse una Massa -Siéntate amet - nulla egestas facilisis. Cras fringilla, ac leo Ullamcorper semper, urna eros pretium lectus, rhoncus nec ligula RISUS eu velita. nulla eu dapibus magna. Sed vehicula tristique Lacinia. Mecenas tincidunt metus en urna consequat ncp congue libero iaculis. Nulla facilisi. Phasellus -sed - sem ut RISUS Mattis accumsan eu -sed ENIM - . Pellentesque habitant morbi tristique senectus et Netus et malesuada famas ac turpis egestas. Suspendisse id est velita, cursus eu quam. Vivamus Lacinia euismod Pretium.
¿Alguna idea?
Solución 2
I finalmente resuelto mis problemas mediante el uso de los meta-caracteres \b
que corresponden a un límite de palabra.
public function filter($value)
{
usort($this->_keywords, function($a,$b){return(strlen($a)<strlen($b));});
foreach ($this->_keywords as $keyword) {
$value = preg_replace(
'/((?<!-)('.$keyword.'\b)(?!\-))/i',
str_replace('%string%', '\2', $this->_wrapper) . '\3',
$value
);
}
return $value;
}
Otros consejos
El más fácil es utilizar preg_replace_callback()
, y coinciden con las palabras que ya ha sido envuelto, y cada palabra clave. Cuando el partido es una palabra que se ha envuelto, apenas la vuelve sin modificar. No hay necesidad de problemáticas mirada-around.
function compare_length($a, $b) {
return strlen($a) < strlen($b);
}
function build_regex($keywords) {
usort($keywords, 'compare_length');
$pieces []= '/(?<wrapped>-[\w\s]*-)|(?<keyword>';
for ($i = 0; $i < count($pieces); $i++) {
if ($i > 0) $pieces []= '|';
$pieces []= preg_quote($keywords[$i], '/');
}
$pieces []= ')/';
return implode("", $pieces);
}
function wrap_callback($match) {
if (!empty($match['wrapped'])) {
return $match['wrapped'];
}
return "-{$match['wrapped']}-";
}
function wrap($text, $keywords) {
$regex = build_regex($keywords);
return preg_replace_callback($regex, 'wrap_callback');
}