2011-05-12 8 views
7

cómo hacer que no tenga hambre - preg_match_all('/"[\p{L}\p{Nd}а-яА-ЯёЁ -_\.\+]+"/ui', $outStr, $matches);cómo hacer regexp no hambriento con comillas?

+1

Creo que el término general es 'flojo' –

+1

@josh: En realidad, es "codicioso". –

+3

En realidad, términos como * codicioso * y * perezoso * son solo atajos coloquiales para términos más largos y más técnicos, atajos que a veces pueden enmascarar lo que realmente está sucediendo. Los términos más técnicos son que los cuantificadores pueden coincidir * como máximo *, * mínimamente * o * posesivamente *, donde '*', '+', '?' Y '{n, m}' son el ** conjunto máximo * *; '*?', '+?', '??' y '{n, m}?' son el ** conjunto mínimo **; y '* +', '++', y '{n, m} +' son el ** conjunto posesivo **. Además, supongo que '? +' Para completar, pero no cambia lo que hace: piénselo. – tchrist

Respuesta

11

¿Se refiere a no codicioso, como para encontrar la pareja más corta en lugar de la más larga? Los cuantificadores *, + y ? son codiciosos por defecto y coincidirán tanto como sea posible. Agregue un signo de interrogación después de ellos para que no sean codiciosos.

preg_match_all('/"[\p{L}\p{Nd}а-яА-ЯёЁ -_\.\+]+?"/ui', $outStr, $matches); 

partido codicioso: partido

"foo" and "bar" 
^^^^^^^^^^^^^^^ 

no expansivo:

"foo" and "bar" 
^^^^^ 
+0

Yeap gracias, he tratado de establecer? símbolo después ", pero no funcionó bien. –

3

Ver: http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php

T (PCRE_UNGREEDY)

Este modificador invierte la "codicia" de los cuantificadores para que no sean codiciosos por defecto, , pero se vuelven codiciosos si van seguidos de?. Es no es compatible con Perl. También puede establecerse mediante un modificador (? U) que establece dentro del patrón o mediante una pregunta marca detrás de un cuantificador (por ejemplo, *?).

+2

¡Ups! Eso significa que PHP y Java usan el indicador' (? U) 'de manera diferente. En PHP enciende el indicador de compilación de expresiones regulares' PCRE_UNGREEDY', pero en JDK7 se enciende 'UNICODE_CHARACTER_CLASS' indicador de compilación de expresiones regulares para hacer que las clases de caracteres se ajusten a la [especificación en expresiones regulares Unicode] (http://www.unicode.org/reports/tr18/#Compatibility_Properties) - que es algo que PHP ya hace por defecto (¡creo!), ya que Perl ya lo hace. Hm, leer la página de manual de * pcrepattern * me deja un poco sospechoso. Parece que solo es '[\ pL \ pN_]', que no es exactamente lo que RL1.2 citado anteriormente quiere. Pero es mejor que ASCII. – tchrist

+5

generalmente es una mala idea usar U (voltear el comportamiento del cuantificador) a menos que realmente sepas lo que estás haciendo. Es mucho más claro y te da más control para voltearlo para cada uno individualmente usando? –

+0

@ Crayon: De acuerdo. – tchrist

2

ou sugirió

/"[\p{L}\p{Nd}а-яА-ЯёЁ -_\.\+]+"/ui 

que presento es equivalente a:

/"[\pL\p{Nd}а-яА-ЯёЁ -_.+]+"/ui 

Para mostrar a la gente lo que no ASCII que está utilizando en caso de que no es evidente, utilizando \x{⋯} escapes que es:

/"[\pL\p{Nd}\x{430}-\x{44F}\x{410}-\x{42F}\x{451}\x{401} -_.+]+"/ui 

Y el uso de caracteres con nombre es:

/"[\pL\p{Nd}\N{CYRILLIC SMALL LETTER A}-\N{CYRILLIC SMALL LETTER YA}\N{CYRILLIC CAPITAL LETTER A}-\N{CYRILLIC CAPITAL LETTER YA}\N{CYRILLIC SMALL LETTER IO}\N{CYRILLIC CAPITAL LETTER IO} -_.+]+"/ui 

Por cierto, los que se producen mediante la ejecución a través de la uniquote script, el primero usando uniquote -x y el segundo usando uniquote -v.

Y sí, sé o al menos creo que PHP aún no admite caracteres con nombre, pero hace que sea más fácil hablar de ello. Además, se asegura de que no hay que confundir las lookalikes:

U+0410 ‹А› \N{CYRILLIC CAPITAL LETTER A} 
U+0430 ‹а› \N{CYRILLIC SMALL LETTER A} 
U+0401 ‹Ё› \N{CYRILLIC CAPITAL LETTER IO} 
U+0451 ‹ё› \N{CYRILLIC SMALL LETTER IO} 

para:

U+0041 ‹A› \N{LATIN CAPITAL LETTER A} 
U+0061 ‹a› \N{LATIN SMALL LETTER A} 
U+00CB ‹Ë› \N{LATIN CAPITAL LETTER E WITH DIAERESIS} 
U+00EB ‹ë› \N{LATIN SMALL LETTER E WITH DIAERESIS} 

Y ahora que pienso en ello, esas son todas las letras, así que no no se puede ver por qué está enumerando la lista cirílica. Es porque no desea todas las letras cirílicas, sino solo ese conjunto particular de ellas? De lo contrario, simplemente haría:

/"[\pL\p{Nd} -_.+]+"/ui 

En ese momento me pregunto acerca de que /i.No puedo ver cuál es su propósito, por lo que habría acaba de escribir:

/"[\pL\p{Nd} -_.+]+"/u 

Como se ha mencionado, el intercambio del máximo cuantificar + por su versión mínima correspondiente, +?, funcionará:

/"[\pL\p{Nd} -_.+]+?"/u 

Sin embargo, me preocupa ese rango de [ -_], es decir, \p{SPACE}-\p{LOW LINE}. Me parece un rango muy peculiar. Significa cualquiera de estos

!"#$%&'()*+,-./:;<=>[email protected][\]^_ 

Por un lado, ha incluido de nuevo las letras mayúsculas ASCII. Por otra parte, usted ha omitido algunos símbolos y signos de puntuación:

% unichars -g '\p{ASCII}' '[\pS\pP]' 'ord() < ord(" ") || ord() > ord("_")' 
` U+0060 GC=Sk GRAVE ACCENT 
{ U+007B GC=Ps LEFT CURLY BRACKET 
| U+007C GC=Sm VERTICAL LINE 
} U+007D GC=Pe RIGHT CURLY BRACKET 
~ U+007E GC=Sm TILDE 

(Esa salida es desde el unichars script, en caso de que usted es curioso.)

que parece extrañamente arbitraria. Así que me pregunto si esto podría no ser lo suficientemente bueno para usted:

/"[\pL\p{Nd}\s\pS\pP]+?"/u 

Ahora que pienso en ello, estos dos podrían causar otros problemas:

U+0401 ‹Ё› \N{CYRILLIC CAPITAL LETTER IO} 
U+0451 ‹ё› \N{CYRILLIC SMALL LETTER IO} 

que asume esos son en forma de NFC (formado por la composición canónica de una descomposición canónica). Si había una posibilidad de que se trata de datos que no se han normalizado a la forma de la NFC, entonces tendría que dar cuenta de

NFD("\N{CYRILLIC CAPITAL LETTER IO}") => "\N{CYRILLIC SMALL LETTER IE}\N{COMBINING DIAERESIS}" 
NFD("\N{CYRILLIC SMALL LETTER IO}") => "\N{CYRILLIC CAPITAL LETTER IE}\N{COMBINING DIAERESIS}" 

Y ahora tienes no letras! El

% uniprops "COMBINING DIAERESIS" 
U+0308 ‹◌̈› \N{COMBINING DIAERESIS} 
    \w \pM \p{Mn} 
    All Any Assigned InCombiningDiacriticalMarks Case_Ignorable CI Combining_Diacritical_Marks Dia Diacritic M Mn Gr_Ext Grapheme_Extend Graph GrExt ID_Continue IDC Inherited Zinh Mark Nonspacing_Mark Print Qaai Word XID_Continue XIDC 

Así que tal vez habría hecho desear:

/"[\pL\pM\p{Nd}\s\pS\pP]+?"/u 

Si quería restringir su cadena para que contenga sólo caracteres que son del latín o cirílico (y no, por ejemplo, el griego o el Katakana), a continuación, se añade una búsqueda hacia delante a tal efecto:

/"(?:(?=[\p{Latin}\p{Cyrillic}])[\pL\pM\p{Nd}\s\pS\pP])+?"/u 

Excepto que también necesita Common de obtener los dígitos y varios puntuation y símbolos, y necesita Inherited para combinar las marcas que siguen a sus letras.Esto nos lleva a esto:

/"(?:(?=[\p{Latin}\p{Cyrillic}\p{Common}\p{Inherited}])[\pL\pM\p{Nd}\s\pS\pP])+?"/u 

que ahora sugiere otra manera de efectuar una coincidencia mínima entre las comillas dobles:

/"(?:(?!")(?=[\p{Latin}\p{Cyrillic}\p{Common}\p{Inherited}])[\pL\pM\p{Nd}\s\pS\pP])+"/u 

que es cada vez de forma complicada de no correr en /x modo:

/ 
    "    # literal double quote 
    (?: 
    ### This group specifies a single char with 
    ### three separate constraints: 

     # Constraint 1: next char must NOT be a double quote 
     (?!") 

     # Constraint 2: next char must be from one of these four scripts 
     (?=[\p{Latin}\p{Cyrillic}\p{Common}\p{Inherited}]) 

     # Constraint 3: match one of either Letter, Mark, Decimal Number, 
     #    whitespace, Symbol, or Punctuation: 
     [\pL\pM\p{Nd}\s\pS\pP] 

    )  # end constraint group 
    +  # repeat entire group 1 or more times 
    "  # and finally match another double-quote 
/ux 

Si se tratara de Perl, escribiría que con m{⋯}xu

m{ 
    "    # literal double quote 
    (?: 
    ### This group specifies a single char with 
    ### three separate constraints: 

     # Constraint 1: next char must NOT be a double quote 
     (?!") 

     # Constraint 2: next char must be from one of these four scripts 
     (?=[\p{Latin}\p{Cyrillic}\p{Common}\p{Inherited}]) 

     # Constraint 3: match one of either Letter, Mark, Decimal Number, 
     #    whitespace, Symbol, or Punctuation: 
     [\pL\pM\p{Nd}\s\pS\pP] 

    )  # end constraint group 
    +  # repeat entire group 1 or more times 
    "  # and finally match another double-quote 
}ux 

Pero no sé si puede hacer delimitadores pareados, de horquillado como ese en PHP.

Espero que esto ayude!