2011-03-16 18 views
8

He creado un patrón de coincidencia en RegexBuddy que se comporta exactamente como esperaba. Pero no puedo transferir esto a Delphi XE, al menos cuando uso la última versión incorporada en TRegEx o TPerlRegEx.Regex llamado grupos de captura en Delphi XE

Mi código de mundo real tiene 6 grupos de captura, pero puedo ilustrar el problema en un ejemplo más fácil. Este código da "3" en el primer diálogo y luego genera una excepción (-7 índice fuera de límites) cuando se ejecuta el segundo diálogo.

var 
    Regex: TRegEx; 
    M: TMatch; 
begin 
    Regex := TRegEx.Create('(?P<time>\d{1,2}:\d{1,2})(?P<judge>.{1,3})'); 
    M := Regex.Match('00:00 X1 90 55KENNY BENNY'); 
    ShowMessage(IntToStr(M.Groups.Count)); 
    ShowMessage(M.Groups['time'].Value); 
end; 

Pero si uso un solo grupo de captura

Regex := TRegEx.Create('(?P<time>\d{1,2}:\d{1,2})'); 

La primera muestra de diálogo "2" y el segundo diálogo mostrará el tiempo "00:00" como se esperaba.

Sin embargo, esto sería un poco limitante si solo se permitiera un grupo de captura con nombre, pero no es el caso ... Si cambio el nombre del grupo de captura a, por ejemplo, "atime".

var 
    Regex: TRegEx; 
    M: TMatch; 
begin 
    Regex := TRegEx.Create('(?P<atime>\d{1,2}:\d{1,2})(?P<judge>.{1,3})'); 
    M := Regex.Match('00:00 X1 90 55KENNY BENNY'); 
    ShowMessage(IntToStr(M.Groups.Count)); 
    ShowMessage(M.Groups['atime'].Value); 
end; 

Voy a obtener "3" y "00:00", tal como esperaba. ¿Hay palabras reservadas que no puedo usar? No lo creo, porque en mi verdadero ejemplo probé nombres completamente aleatorios. Simplemente no puedo entender qué causa este comportamiento.

+0

debe informar esto en QC, ya que esto es obviamente un error. – jachguate

Respuesta

7

Cuando pcre_get_stringnumber no encuentra el nombre, se devuelve PCRE_ERROR_NOSUBSTRING.

PCRE_ERROR_NOSUBSTRING se define en RegularExpressionsAPI como PCRE_ERROR_NOSUBSTRING = -7.

Algunas pruebas muestran que los rendimientos pcre_get_stringnumberPCRE_ERROR_NOSUBSTRING por cada nombre que tiene la primera letra en el rango de k a z y que alcance depende de la primera letra en judge. Cambiar judge a otra cosa cambia el rango.

Como yo lo veo, hay al menos dos errores involucrados aquí. Uno de cada pcre_get_stringnumber y uno en TGroupCollection.GetItem que necesita para levantar una excepción adecuada en lugar de SRegExIndexOutOfBounds

+0

Muchas gracias por profundizar en el problema a este nivel. Encontré una solución alternativa utilizando la biblioteca TPerlRegEx del autor de RegexBuddy. Como he entendido, esta biblioteca constituye la base para la implementación de XE, por lo que encuentro las diferencias muy misteriosas. –

+0

+1, buen hallazgo. – jachguate

5

El error parece estar en la unidad RegularExpressionsAPI que envuelve la biblioteca PCRE, o en los archivos OBJ PCRE que se vincula. Si me quedo este código:

program Project1; 

{$APPTYPE CONSOLE} 

uses 
    SysUtils, RegularExpressionsAPI; 

var 
    myregexp: Pointer; 
    Error: PAnsiChar; 
    ErrorOffset: Integer; 
    Offsets: array[0..300] of Integer; 
    OffsetCount, Group: Integer; 

begin 
    try 
    myregexp := pcre_compile('(?P<time>\d{1,2}:\d{1,2})(?P<judge>.{1,3})', 0, @error, @erroroffset, nil); 
    if (myregexp <> nil) then begin 
     offsetcount := pcre_exec(myregexp, nil, '00:00 X1 90 55KENNY BENNY', Length('00:00 X1 90 55KENNY BENNY'), 0, 0, @offsets[0], High(Offsets)); 
     if (offsetcount > 0) then begin 
     Group := pcre_get_stringnumber(myregexp, 'time'); 
     WriteLn(Group); 
     Group := pcre_get_stringnumber(myregexp, 'judge'); 
     WriteLn(Group); 
     end; 
    end; 
    except 
    on E: Exception do 
     Writeln(E.ClassName, ': ', E.Message); 
    end; 
    ReadLn; 
end. 

Imprime -7 y 2 en lugar de 1 y 2.

Si quito RegularExpressionsAPI de la cláusula uses y añadir a la unidad pcre de mi TPerlRegEx component, entonces se hace correctamente impresión 1 y 2.

el RegularExpressionsAPI en Delphi XE se basa en mi unidad de pcre, y la unidad de RegularExpressionsCore se basa en mi unidad de PerlRegEx. Embarcadero hizo algunos cambios en ambas unidades. También compilaron sus propios archivos OBJ de la biblioteca PCRE que están vinculados por RegularExpressionsAPI.

he informado de este error como QC 92497

También he creado un informe separado QC 92498 de solicitar que TGroupCollection.GetItem provocará una excepción más sensibles al solicitar un grupo con nombre que no existe.(Este código está en la unidad RegularExpressions que se basa en el código escrito por Vincent Parrett, no en mí)