2015-07-31 5 views
8

perldoc perlre dice questo:Parentesi graffa sinistra deprecata in Perl regex - esattamente quando?

(Se una parentesi graffa si verifica in qualsiasi altro contesto e non fa parte di una sequenza backslash come \x{...}, viene trattato come un normale carattere Tuttavia, un avvertimento deprecazione è. sollevato per tutte queste occorrenze di , e in Perl v5.26, gli usi letterali di una parentesi graffa saranno obbligati a fuggire, ad esempio precedendoli con una barra rovesciata ("\{") o racchiudendoli tra parentesi quadre ("[{]"). modifica consentirà future estensioni di sintassi (come la modifica del livello basso er legato di un quantificatore opzionale), e una migliore controllo degli errori di quantificatori.)

OK, quindi il seguente stampa il messaggio deprecazione.

perl -lE 'm/x{x}/' 

Perché non segue?

perl -lE 'm/x({x})/' 

ad es. nel gruppo di cattura è il { consentito senza caratteri di escape? Probabilmente non perché

perl -lE 'm/x(x{x})/' 

stampa anche l'avviso.

Quindi, qual è l'esatta "logica"?

P.S .: Sfuggirò ad ogni letterale {, ma mi sto chiedendo quale sia la logica alla base di quanto sopra.

+0

Mi sembra che dovrebbe mettere in guardia anche. – ikegami

risposta

5

L'avvertimento viene emesso solo quando il riccio:

  • non è all'inizio del pattern
  • segue un carattere alfabetico
  • non è parte di un special escape sequence\b{}, \B{}, \g{}, \k{}, \N{} , \o{}, \p{}, \P{} o \x{}
  • non è parte di un quantificatore della forma {n}, {n,}, o {n,m}, dove n e m sono interi positivi

See regcomp.c nella sorgente di Perl (il sotto è da 5.22.0):

 case '{': 
      /* Currently we don't warn when the lbrace is at the start 
      * of a construct. This catches it in the middle of a 
      * literal string, or when its the first thing after 
      * something like "\b" */ 
      if (! SIZE_ONLY 
       && (len || (p > RExC_start && isALPHA_A(*(p -1))))) 
      { 
       ckWARNregdep(p + 1, "Unescaped left brace in regex is deprecated, passed through"); 
      } 
      /*FALLTHROUGH*/ 
     default: /* A literal character */ 
      normal_default: 
      if (UTF8_IS_START(*p) && UTF) { 
       STRLEN numlen; 
       ender = utf8n_to_uvchr((U8*)p, RExC_end - p, 
             &numlen, UTF8_ALLOW_DEFAULT); 
       p += numlen; 
      } 
      else 
       ender = (U8) *p++; 
      break; 
     } /* End of switch on the literal */ 

Demo:

$ perl -e '/{/' # Beginning of pattern, no warning 

$ perl -e '/.{/' # Doesn't follow alpha, no warning 

$ perl -e '/x{3}/' # Valid quantifier, no warning 

$ perl -e '/\x{/' # Part of special escape sequence \x{}, different warning 
Missing right brace on \x{} in regex; marked by <-- HERE in m/\x{ <-- HERE/at -e line 1. 

$ perl -e '/x{/' # Follows alpha, isn't a quantifier or special escape, warns 
Unescaped left brace in regex is deprecated, passed through in regex; marked by <-- HERE in m/x{ <-- HERE/at -e line 1. 
+0

Il commento lo spiega. Probabilmente, il 5.24 avvertirà di più. ;) Grazie per aver trovato questo. – jm666

-1

La logica è di emettere l'avviso quando {...} si trova in un contesto che potrebbe significare "corrispondere qualcosa un certo numero di volte" e non emetterlo quando significa qualcos'altro.

Sostituiamo {x} con {3} e pensiamo alla regex.

Il tuo primo esempio, /x{3}/ significa partita x tre squadre: "xxx"

Il tuo ultimo esempio, /x(x{3})/, significa partita x e poi abbinare x tre volte, catturando la stringa di 3 x 's in un gruppo

In /x({3})/, lo {3} si trova in un gruppo di acquisizione da solo e quindi significa "corrisponde a qualcosa 3 volte". In modo univoco significa corrispondere allo x e quindi corrispondere alla stringa letterale {3}, inserendola in un gruppo di acquisizione.

+0

Ma non è quello che dice la documentazione, che è fondamentalmente che si otterrà un avviso di deprecazione se si utilizza una parentesi letterale in un modello regex senza che sia sfuggito – Borodin

+0

Che si tratti di un bug rende una buona illustrazione di * perché * questo cambiamento è stato fatto. –

+0

e per '/ (x) {x} /' - seguendo la logica, dovrebbe emettere l'avviso, perché '/ (x) {x} /' non è una corrispondenza univoca ... ma nessun avvertimento .. – jm666

1

Questo è un bug, nella documentazione o nel compilatore regex.Non sono sicuro che importi molto anche se

Ad una congettura selvaggia, il codice per sollevare l'avviso è stato scritto per la situazione in cui ciò che è all'interno delle parentesi non sembra \d+(?:,\d+)? ma non per quando non c'è niente prima del l'apertura di parentesi graffa di quantificare

per esempio, accetta le parentesi graffe come testo e avverte con qualcosa come /x{4x}/ o /x{4,x}/, ma non avvisa per /{3,4}/, /x({3,4})/ o /x(a|{3,4})/

0

Ci è un bug in cui non sono state segnalate le parentesi graffe di sinistra senza escape. Non è corretto in nessuna versione stabile, ma è disponibile nella attuale serie di sviluppo 5.25. Stabile 5.26, che verrà rilasciato approssimativamente a maggio dovrebbe avere questo problema.

ma la documentazione è stata chiarita, e qui è:

Blockquote La semplice regola da ricordare, se si vuole partita un letterale "{" carattere (U + 007B "LEFT RICCIA SUPPORTO ") in un modello di espressione regolare , è di sfuggire ad ogni istanza letterale di esso in qualche modo. Generalmente più semplice è precederlo con una barra rovesciata, come "{" o racchiuderlo tra parentesi quadre ("[{]"). Se il modello delimitatori sono parentesi graffe anche, ogni parentesi graffa chiusa corrispondente ("}") dovrebbe anche essere scappato per evitare di confondere il parser, per esempio,

 qr{abc\{def\}ghi} 

    Forcing literal "{" characters to be escaped will enable the Perl 
    language to be extended in various ways in future releases. To avoid 
    needlessly breaking existing code, the restriction is is not enforced 
    in contexts where there are unlikely to ever be extensions that could 
    conflict with the use there of "{" as a literal. 

    In this release of Perl, some literal uses of "{" are fatal, and some 
    still just deprecated. This is because of an oversight: some uses of a 
    literal "{" that should have raised a deprecation warning starting in 
    v5.20 did not warn until v5.26. By making the already-warned uses 
    fatal now, some of the planned extensions can be made to the language 
    sooner. 

    The contexts where no warnings or errors are raised are: 

    * as the first character in a pattern, or following "^" indicating 
     to anchor the match to the beginning of a line. 

    * as the first character following a "|" indicating alternation. 

    * as the first character in a parenthesized grouping like 

      /foo({bar)/ 
      /foo(?:{bar)/ 

    * as the first character following a quantifier 

      /\s*{/