web-dev-qa-db-fra.com

Regex: modèle de correspondance tant qu'il n'est pas au début

Supposons les chaînes suivantes:

aaa bbb ccc
bbb aaa ccc

Je veux faire correspondre aaa tant qu'il n'est pas au début de la chaîne. J'essaie de le nier en faisant quelque chose comme ceci:

[^^]aaa

Mais je ne pense pas que ce soit juste. En utilisant preg_replace.

31

Vous pouvez utiliser un regard derrière pour vous assurer que ce n'est pas au début. (?<!^)aaa

49
Joe

Depuis que je suis venu ici via la recherche Google et que j'étais intéressé par une solution qui n'utilise pas de lookbehind , voici mes 2 cents.

Le [^^]aaa le motif correspond à un caractère autre que ^ puis 3 as n'importe où à l'intérieur d'une chaîne. Le [^...] est un classe de caractères niés^ n'est pas considéré comme un caractère spécial. Notez le premier ^ c'est juste après [ est spécial car il dénote une négation, et le second n'est qu'un symbole littéral caret.

Ainsi, un ^ ne peut pas être à l'intérieur [...] pour indiquer le début de la chaîne.

Une solution consiste à utiliser n'importe quel lookaround négatif, ces deux fonctionneront également bien:

(?<!^)aaa

et une anticipation:

(?!^)aaa

Pourquoi Lookahead fonctionne aussi? Lookarounds sont des assertions de largeur nulle, et les ancres sont également de largeur nulle - elles ne consomment pas de texte. Littéralement parlant, (?<!^) vérifie s'il n'y a pas de début de position de chaîne immédiatement à gauche de l'emplacement actuel, et (?!^) vérifie s'il n'y a pas de début de position de chaîne immédiatement à droite de l'emplacement actuel. Les mêmes emplacements sont vérifiés, c'est pourquoi les deux fonctionnent bien.

21

Si vous ne voulez pas utiliser lookbehind, utilisez cette expression régulière:

/.(aaa)/

Et utilise matched group # 1.

12
anubhava

Cette situation est la première fois que je vois des contournements surperformer \K. Intéressant.

En règle générale, la capture de groupes et de contournements coûte des étapes supplémentaires. Mais en raison de la nature de cette tâche, le moteur d'expression régulière peut parcourir la chaîne plus rapidement à la recherche du aaa puis regarder en arrière pour un début de l'ancre de chaîne.

Je vais ajouter quelques modèles \K Pour comparaison.

J'utilise le modificateur de modèle s au cas où le caractère de tête pourrait être un caractère de nouvelle ligne (auquel . Ne correspondrait pas normalement). Je pensais simplement que j'ajouterais cette considération pour aborder de manière préventive une affaire marginale qui pourrait m'être posée.

Encore une fois, c'est un scénario instructif parce que dans tous les autres cas de regex que j'ai traités, \K Bat les autres techniques.

Matrice de comparaison du nombre de pas:

              | `~.\Kaaa~s` | `~.+?\Kaaa~s` | `(?<!^)aaa` | `(?!^)aaa` | `.(aaa)` |
--------------|-------------|---------------|-------------|------------|----------|
`aaa bbb ccc` |   12 steps  |    67 steps   |   8 steps   |  8 steps   | 16 steps |
--------------|-------------|---------------|-------------|------------|----------|
`bbb aaa ccc` |   15 steps  |    12 steps   |   6 steps   |  6 steps   | 12 steps |

À retenir: Pour en savoir plus sur l'efficacité de vos modèles, crachez-les dans regex101.com et comparez le nombre de pas.

De plus, si vous savez exactement quelle sous-chaîne vous recherchez et que vous n'avez pas besoin d'un modèle d'expression régulière, alors vous devriez utiliser strpos() comme une bonne pratique (et juste vérifiez que la valeur retournée est > 0).

2
mickmackusa

Cela fonctionnera pour trouver ce que vous cherchez:

(?<!^)aaa

Exemple d'utilisation: http://regexr.com?34ab2

1
Daedalus

Je suis venu ici pour étudier une solution pour le moteur re2, utilisé par les feuilles de calcul Google, qui ne prend pas en charge les contournements. Mais les réponses ici m'ont donné l'idée d'utiliser ce qui suit. Je ne comprends pas pourquoi je dois remplacer par le groupe capturé mais de toute façon, cela fonctionne.

aaa bbb ccc
bbb aaa ccc

([^^])aaa

remplacer par:

$1zzz

réutilisés dans:

aaa bbb ccc
bbb zzz ccc

0
Timar Ivo Batis