Обычно это кто-то, кто советует использовать анализатор HTML. И действительно, это было бы более надежным для этой задачи. Обычно QueryPath или phpQuery также проще для глаз:
$p = phpQuery::newDocumentHTML($h);
$p->find("p")->not("span")->wrap("span");
Но в этом случае я потерпел неудачу. Это немного черное искусство, если вы не знаете всех волшебных селекторов jQuery (а в phpQuery их все равно нет). Ваш случай сложен, так как вы хотите работать с отдельными текстовыми узлами. Следовательно, вам действительно придется использовать DOMDocument для индивидуального сканирования документа. Это, конечно, выполнимо, но слишком много API для меня. :}
Так что я пропустил прямо к подходу регулярных выражений, который с большой осторожностью был бы реально осуществим:
print preg_replace(
'#(?<!<span)>(\s*)(\w[\w,.\h]+)(\s*)<#',
'>$1<span>$2</span>$3<',
$html);
Фактический трюк - это утверждение за кадром (?<!<span)
, поэтому он не будет соответствовать тексту, уже заключенному в промежутки. Это выглядит более запутанным, потому что я сделал так, чтобы он совпадал с пробелами \s
и горизонтальными \h
по отдельности и включил его в более приятную структуру вывода. Вам нужно будет изменить [\w,.\h]
, чтобы включить все возможные дополнительные символы в последнюю строку. Вот где подход регулярных выражений показывает его слабость - вы не можете позволить ему соответствовать <
или >
. И если ваши текстовые строки на самом деле являются абзацами, вам придется отменить разделение \ s и \ h.
Итак, снова работает для вашего простого случая. Но DOM-подходы обычно более надежны .