Avertissement: preg replace(): Unknown modificateur ']'

j'ai l'erreur suivante :

Avertissement: preg_replace(): Unknown modificateur ']' dans xxx.php sur la ligne 38

c'est le code de la ligne 38:

<?php echo str_replace("</ul></div>", "", preg_replace("<div[^>]*><ul[^>]*>", "", wp_nav_menu(array('theme_location' => 'nav', 'echo' => false)) )); ?>

quelqu'un Peut-il m'aider à résoudre ce problème?

31
demandé sur Rizier123 2013-12-20 18:05:39
la source

2 ответов

pourquoi l'erreur se produit

en PHP, une expression régulière doit être incluse dans une paire de délimiteurs . Un délimiteur peut être n'importe quel caractère non-alphanumérique, Non-backslash, non-whitespace; / , # , ~ sont les plus couramment utilisés. Notez qu'il est également possible d'utiliser des délimiteurs de style bracket où les délimiteurs d'ouverture et de fermeture sont les délimiteurs de début et de fin, i.e. <pattern_goes_here> , [pattern_goes_here] etc. sont toutes valides.

" Inconnu modificateur X " erreur se produit généralement dans les deux cas suivants:

  • lorsque votre expression habituelle est délimiteurs manquants .

  • lorsque vous utilisez le délimiteur à l'intérieur de le motif sans échapper à it.

Dans ce cas, l'expression régulière est <div[^>]*><ul[^>]*> . Le moteur regex considère tout de < à > comme le modèle regex, et tout par la suite comme des modificateurs.

Regex: <div[^>  ]*><ul[^>]*>
       │     │  │          │
       └──┬──┘  └────┬─────┘
       pattern    modifiers

] voici un modificateur inconnu, car il apparaît après la fermeture du délimiteur > . C'est pourquoi PHP jette cette erreur.

selon le modèle, la plainte modificateur inconnu aurait aussi bien pu être environ * , + , p , / ou ) ou presque toute autre lettre/symbole. Seuls les imsxeADSUXJu sont des modificateurs PCRE valides .

comment le fixer

le fix est facile. Il suffit d'envelopper votre motif regex avec des délimiteurs valides. Dans ce cas, vous pouvez choisir ~ et obtenir le suivant:

~<div[^>]*><ul[^>]*>~
│                   │
│                   └─ ending delimiter
└───────────────────── starting delimiter

si vous recevez cette erreur Bien que vous ayez utilisé un délimiteur, c'est peut-être parce que le motif lui-même contient des occurrences non enregistrées dudit délimiteur.

Ou d'échapper à des délimiteurs

/foo[^/]+bar/i serait certainement jeter une erreur. Donc vous pouvez y échapper en utilisant un \ antislash si elle apparaît n'importe où dans le regex:

/foo[^\/]+bar/i
│      │     │
└──────┼─────┴─ actual delimiters
       └─────── escaped slash(/) character

c'est un travail fastidieux si votre motif regex contient autant d'occurrences du caractère de délimiteur.

la manière la plus propre, bien sûr, serait d'utiliser un délimiteur tout à fait différent. Idéalement un caractère qui n'apparaît nulle part dans le motif regex, dites # - #foo[^/]+bar#i .

plus de lecture:

70
répondu Amal Murali 2017-05-23 15:34:53
la source

autres exemples

Le "1519690920 référence de" réponse explique la raison pour laquelle "Inconnu" mises en garde. C'est juste une comparaison d'autres variantes typiques.

  • en oubliant d'ajouter regex / délimiteurs / , le premier symbole non littéral sera supposé être un. Par conséquent, l'avertissement est souvent sur ce qui suit un groupe (…) , […] méta-symbole:

    preg_match("[a-zA-Z]+:\s*.$"
                ↑      ↑⬆
    
  • parfois votre regex utilise déjà un délimiteur personnalisé ( : ici), mais contient toujours le même caractère que le littéral non enregistré. Il est alors confondu comme délimiteur prématuré. C'est pourquoi le symbole suivant reçoit le trophée "modificateur inconnu":

    preg_match(":\[[\d:/]+\]:"
                ↑     ⬆     ↑
    
  • lorsque vous utilisez le délimiteur classique / , veillez à ne pas l'avoir à l'intérieur du regex littéralement. Cela se produit le plus souvent en essayant de faire correspondre noms de fichiers non enregistrés :

    preg_match("/pathname/filename/i"
                ↑        ⬆         ↑
    

    ou lorsque l'angle de correspondance/le style de support carré tags :

    preg_match("/<%tmpl:id>(.*)</%tmpl:id>/Ui"
                ↑               ⬆         ↑
    
  • Templating-style (Smarty ou BBCode) regex patterns Require often {…} or […] brackets. Les deux devraient normalement être évadés. (Une paire extérieure {} étant la une exception tout de même).

    ils sont aussi mal interprétés comme les délimiteurs appariés quand aucun délimiteur réel n'est utilisé. Si ils sont alors également utilisé comme caractère littéral, alors que, bien sûr ... une erreur.

    preg_match("{bold[^}]+}"
                ↑      ⬆  ↑
    
  • chaque fois que l'avertissement dit" le délimiteur ne doit pas être alphanumérique ou antislash "alors vous avez aussi complètement oublié les délimiteurs:

    preg_match("ab?c*"
                ↑
    
  • " unkown modifier 'g' " indique souvent un regex qui a été copié verbatimly à partir de JavaScript ou Perl.

    preg_match("/abc+/g"
                      ⬆
    

    PHP n'utilise pas le drapeau mondial /g . Au lieu de cela, la fonction preg_replace fonctionne sur toutes les occurences, et preg_match_all est le pendentif de recherche "global" à la seule occurence preg_match .

    donc, il suffit de supprimer le drapeau /g .

    Voir aussi:

    · Avertissement: preg_replace(): Unknown modificateur "g'

    · preg_replace: bad regex = = "Inconnu Modificateur"?

  • un cas plus particulier concerne le PCRE_EXTENDUE /x drapeau . C'est souvent (ou devrait être) utilisé pour rendre regexps plus élevé et lisible.

    cela permet d'utiliser inline # commentaires. PHP implémente les délimiteurs regex au sommet du PCRE. Mais il ne traite pas # d'une manière spéciale. C'est ainsi qu'un délimiteur littéral dans un commentaire # peut devenir une erreur:

    preg_match("/
       ab?c+  # Comment with / slash in between
    /x"
    

    (il convient également de noter que l'utilisation de # comme délimiteur #abc+#x peut être doublement déconseillée.)

  • L'interpolation des variables dans une regex exige qu'elles soient pré-échappées, ou qu'elles soient elles-mêmes des regexps valides. Vous ne pouvez pas dire à l'avance si cela va fonctionner:

     preg_match("/id=$var;/"
                 ↑    ↺   ↑
    

    il est préférable d'appliquer $var = preg_quote($var, "/") dans de tels cas.

    Voir aussi:

    · Inconnu modificateur '/'...? quel est-il?

    une autre alternative est d'utiliser \Q…\E s'échappe pour non cotées chaînes littérales:

     preg_match("/id=\Q{$var}\E;/mix");
    

    notez qu'il s'agit simplement d'un raccourci pratique, pas fiable/sûr. Elle s'effondrerait si $var contenait elle-même un '\E' littéral (bien que peu probable).

  • modificateur déprécié /e est un problème entièrement différent. Cela n'a rien à voir avec les délimiteurs, mais l'expression implicite le mode d'interprétation est progressivement abandonné. Voir aussi: remplacer preg_replace /e dépréciée par preg_replace_callback

délimiteurs alternatifs regex

comme déjà mentionné, la solution la plus rapide à cette erreur est simplement de choisir un délimiteur distinct. Tout symbole non-lettre peut être utilisé. On préfère souvent les caractères distinctifs sur le plan visuel:

techniquement, vous pouvez utiliser $abc$ ou |abc| pour les délimiteurs. Cependant, il est préférable d'éviter les symboles qui servent de méta-caractères regex eux-mêmes.

le hachage # comme délimiteur est plutôt populaire aussi. Mais il faut faire attention en combinaison avec le modificateur de lisibilité x / PCRE_EXTENDED . Vous ne pouvez donc pas utiliser les commentaires # inline ou (?#…) , car ceux-ci seraient confondus en tant que délimiteurs.

délimiteurs de guillemets seulement

de temps en temps vous voyez " et ' utilisés comme délimiteurs regex appariés avec leur conterpart comme enclos PHP string:

  preg_match("'abc+'"
  preg_match('"abc+"'

qui est parfaitement valide en ce qui concerne PHP. C'est parfois commode et discret, mais pas toujours lisible dans les IDEs et les éditeurs.

paires de délimiteurs

une variante intéressante sont des délimiteurs appariés. Au lieu d'utiliser le même symbole sur les deux extrémités d'un regex, vous pouvez utiliser <...> (...) [...] {...} combinaison support / entretoise.

  preg_match("(abc+)"   # just delimiters here, not a capture group

alors que la plupart d'entre eux servent aussi regex méta-caractères, vous pouvez souvent utiliser sans effort supplémentaire. Aussi longtemps que ces supports/parens spécifiques dans le regex sont appariés ou échappés correctement, ces variantes sont tout à fait lisibles.

délimiteurs de Fancy regex

un truc un peu paresseux (qui n'est pas endossé ici) est d'utiliser des caractères ASCII non imprimables comme délimiteurs. Cela fonctionne facilement en PHP en utilisant des guillemets doubles pour la chaîne regex, et des évasions octales pour les délimiteurs:

 preg_match(""1519120920"1 abc+ "1519120920"1mix"

le "1519580920"1 est juste un caractère de contrôle GIP qui n'est pas habituellement nécessaire. Par conséquent, il est très peu probable d'apparaître dans la plupart des modèles regex. Qui le rend approprié ici, même si pas très lisible.

malheureusement, vous ne pouvez pas utiliser Unicode glyps comme délimiteurs. PHP ne permet que les caractères à un octet. Et pourquoi est-ce? Eh bien, content que vous ayez demandé:

délimiteurs PHPs atop PCRE

les fonctions preg_* utilisent le moteur PCRE regex, qui lui-même ne se soucie pas ou ne prévoit pas de délimiteurs. Pour la ressemblance avec Perl les fonctions preg_* les mettent en œuvre. C'est aussi pourquoi vous pouvez utiliser modifier les lettres /ism au lieu de simplement constantes comme paramètre .

voir ext/pcre / php_pcre.c sur la façon dont la chaîne regex est analysée:

  • tout d'abord, tous les espaces principaux sont ignorés.

  • tout symbole non alphanumérique est considéré comme délimiteur présumé. Notez que PHP n'honore que les caractères à un octet:

    delimiter = *p++;
    if (isalnum((int)*(unsigned char *)&delimiter) || delimiter == '\') {
            php_error_docref(NULL,E_WARNING, "Delimiter must not…");
            return NULL;
    }
    
  • le reste de la chaîne regex est traversé de gauche à droite. Uniquement antislash \ -échappé symboles sont ignorés.

  • si le délimiteur est retrouvé, le reste est vérifié pour ne contenir que des lettres modificatrices.

  • si le délimiteur est l'un des ([{< )]}> )]}> bracelets/consoles, alors la logique de traitement est plus élaborée.

    int brackets = 1;   /* brackets nesting level */
    while (*pp != 0) {
            if (*pp == '\' && pp[1] != 0) pp++;
            else if (*pp == end_delimiter && --brackets <= 0)
                    break;
            else if (*pp == start_delimiter)
                    brackets++;
            pp++;
    }
    

    cherche délimiteur gauche et droit correctement apparié, mais ignore les autres braces / brackets types lors du comptage.

  • la chaîne brute regex est passée au PCRE backend seulement après que les drapeaux delimiter et modifier ont été coupés.

tout ceci n'est pas pertinent. Mais explique d'où le délimiteur avertissements viennent. Et toute cette procédure doit avoir un minimum de compatibilité Perl. Il y a quelques déviations mineures bien sûr, comme le […] classe de caractère Contexte pas recevoir un traitement spécial en PHP.

autres références

14
répondu mario 2017-05-23 15:18:24
la source

Autres questions sur php regex wordpress preg-replace