Insérer un espace après un point-virgule, sauf s’il fait partie d’une entité HTML

J’essaie d’insérer un espace après chaque point-virgule, sauf si le point-virgule fait partie d’une entité HTML. Les exemples sont courts, mais mes chaînes peuvent être assez longues, avec plusieurs points-virgules (ou aucun).

Coca‑Cola => Coca‑Cola (‑ is a non-breaking hyphen) Beverage;Food;Music => Beverage; Food; Music 

J’ai trouvé l’expression régulière suivante qui fait l’affaire pour les chaînes courtes:

 <?php $a[] = 'Coca‑Cola'; $a[] = 'Beverage;Food;Music'; $regexp = '/(?:&#?\w+;|[^;])+/'; foreach ($a as $str) { echo ltrim(preg_replace($regexp, ' $0', $str)).'
'; } ?>

Toutefois, si la chaîne est un peu volumineuse, le preg_replace ci-dessus bloque en fait mon serveur Apache (la connexion au serveur a été réinitialisée pendant le chargement de la page). Ajoutez ce qui suit au code exemple ci-dessus:

 $a[] = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. '. 'In blandit metus arcu. Fusce eu orci nulla, in interdum risus. '. 'Maecenas ut velit turpis, eu pretium libero. Integer molestie '. 'faucibus magna sagittis posuere. Morbi volutpat luctus turpis, '. 'in pretium augue pellentesque quis. Cras tempor, sem suscipit '. 'dapibus lacinia, dolor sapien ulsortingces est, eget laoreet nibh '. 'ligula at massa. Cum sociis natoque penatibus et magnis dis '. 'parturient montes, nascetur ridiculus mus. Phasellus nulla '. 'dolor, placerat non sem. Proin tempor tempus erat, facilisis '. 'euismod lectus pharetra vel. Etiam faucibus, lectus a '. 'scelerisque dignissim, odio turpis commodo massa, vitae '. 'tincidunt ante sapien non neque. Proin eleifend, lacus et '. 'luctus pellentesque;odio felis.'; 

Le code ci-dessus (avec la grande chaîne) plante Apache mais fonctionne si je lance PHP sur la ligne de commande.

Ailleurs dans mon programme, j’utilise preg_replace sur des chaînes beaucoup plus grandes sans problème, donc je devine quelque chose que l’expression régulière dépasse PHP / Apache.

Y a-t-il un moyen de “réparer” la regex pour qu’elle fonctionne sur Apache avec de grandes chaînes ou existe-t-il un autre moyen plus sûr de le faire?

J’utilise PHP 5.2.17 avec Apache 2.0.64 sur Windows XP SP3, si cela peut vous aider. (Malheureusement, mettre à jour PHP ou Apache n’est pas une option pour le moment.)

Je suggère cette expression de correspondance:

 \b(? 

... qui correspond à une série de caractères (lettres, chiffres et tiret bas) qui n'est pas précédée d'une esperluette (ou d'une esperluette suivie d'un symbole de hachage) mais qui est suivie d'un point-virgule.

cela signifie que:

 \b # assert that this is a word boundary (? 

remplacer par la chaîne '$0 '

laissez-moi savoir si cela ne fonctionne pas pour vous

Bien sûr, vous pourriez aussi utiliser [a-zA-Z0-9] au lieu de \w pour éviter de faire correspondre un point-virgule, mais je ne pense pas que cela vous causerait des problèmes

Vous devrez peut- être également échapper au symbole de hachage (car il s'agit du symbole de commentaire regex), comme ceci:

 \b(? 

EDIT Pas sûr, mais je suppose que mettre le terme limite au début va le rendre un peu plus efficace (et donc moins susceptible de faire planter votre serveur), donc j'ai changé cela dans les expressions et la panne. ..

EDIT 2 ... et un peu plus d'informations sur la raison pour laquelle votre expression pourrait faire planter votre serveur: Backtracking catastrophique - Je pense que cela s'applique (?) Hmmm .... bonne information néanmoins

EDIT FINAL si vous cherchez à append uniquement un espace après un point - virgule s'il n'y a pas déjà d'espaces (c.-à-d. En append une dans le cas de pellentesque;odio mais pas dans le cas de pellentesque; odio ) la fin, ce qui empêchera d'append des espaces inutiles supplémentaires:

 \b(? 

Vous pouvez utiliser un regard négatif:

 preg_replace('/(?<=[^\d]);([^\s])/', '; \1', $text) 

Non testé car je n'ai pas d'ordinateur à scope de main, mais cela ou une légère variation devrait fonctionner.

Avec un problème comme celui-ci, un rappel peut aider.

 (&(?:[A-Za-z_:][\w:.-]*|\#(?:[0-9]+|x[0-9a-fA-F]+)))?; 

Étendu

 ( # Capture buffer 1 & # Ampersand '&' (?: [A-Za-z_:][\w:.-]* # normal words | \# # OR, code '#' (?: [0-9]+ # decimal | x[0-9a-fA-F]+ # OR, hex 'x' ) ) )? # End capture buffer 1, optional ; # Semicolon ';' 

Testcase http://ideone.com/xYrpg