2012-07-09 17 views
8

Estoy escribiendo una utilidad grep en Lua para nuestros dispositivos móviles con Windows CE 6/7, pero me he encontrado con algunos problemas para implementar patrones de coincidencia insensibles a mayúsculas y minúsculas. La solución obvia de convertir todo a mayúsculas (o menos) no funciona tan simplemente debido a las clases de caracteres.Igualación de patrones Lua insensible a las mayúsculas

La única otra cosa en la que puedo pensar es convertir los literales en el mismo patrón en mayúsculas.

Esto es lo que tengo hasta ahora:

function toUpperPattern(instr) 
    -- Check first character 
    if string.find(instr, "^%l") then 
     instr = string.upper(string.sub(instr, 1, 1)) .. string.sub(instr, 2) 
    end 
    -- Check the rest of the pattern 
    while 1 do 
     local a, b, str = string.find(instr, "[^%%](%l+)") 
     if not a then break end 
     if str then 
      instr = string.sub(instr, 1, a) .. string.upper(string.sub(instr, a+1, b)) .. string.sub(instr, b + 1) 
     end 
    end 
    return instr 
end 

Tengo que reconocer cuánto tiempo se tardó en llegar, incluso tan lejos, y todavía se puede ver de inmediato que van a haber problemas con cosas como ciento escapado signos '%%'

Pensé que esto debe ser un problema bastante común, pero parece que no puedo encontrar mucho sobre el tema. ¿Hay formas más fáciles (o al menos completas) de hacer esto? Estoy empezando a volverme loco aquí ... ¡Espero que los gurús de Lua puedan iluminarme!

Respuesta

9

intentar algo como esto:

function case_insensitive_pattern(pattern) 

    -- find an optional '%' (group 1) followed by any character (group 2) 
    local p = pattern:gsub("(%%?)(.)", function(percent, letter) 

    if percent ~= "" or not letter:match("%a") then 
     -- if the '%' matched, or `letter` is not a letter, return "as is" 
     return percent .. letter 
    else 
     -- else, return a case-insensitive character class of the matched letter 
     return string.format("[%s%s]", letter:lower(), letter:upper()) 
    end 

    end) 

    return p 
end 

print(case_insensitive_pattern("xyz = %d+ or %% end")) 

que imprime:

[xX][yY][zZ] = %d+ [oO][rR] %% [eE][nN][dD]
+1

Impresionante. Estaba dibujando un espacio en blanco. Por cierto: puedes decir 'pattern: gsub' justo como dijiste' letter: lower'. Incluso podría decir '('[% s% s]'): format' pero eso es un poco más extraño. – Mud

+0

Sí, 'string.format (...)' parece más familiar que '('[% s% s]'): formato (...)', pero me gusta el 'patrón: gsub (...) 'mejor! Gracias. –

+0

Increíble. Pero una pregunta ... ¿Cómo eso no convierte algo así como '%% test' en' %% [tT] est'? ¿Se salta esa coincidencia porque la iteración anterior habría coincidido con '%%'? Quizás mi cerebro esté un poco frito hoy:/ – Nubbychadnezzar

0

Lua 5.1, LPEG v0.12

do 
    local p = re.compile([[ 
     pattern <- ({b}/{escaped}/brackets/other)+ 
     b  <- "%b" . . 
     escaped <- "%" . 
     brackets <- { "[" ([^]%]+/escaped)* "]" } 
     other <- [^[%]+ -> cases 
    ]], { 
     cases = function(str) return (str:gsub('%a',function(a) return '['..a:lower()..a:upper()..']' end)) end 
    }) 
    local pb = re.compile([[ 
     pattern <- ({b}/{escaped}/brackets/other)+ 
     b  <- "%b" . . 
     escaped <- "%" . 
     brackets <- {: {"["} ({escaped}/bcases)* {"]"} :} 
     bcases <- [^]%]+ -> bcases 
     other <- [^[%]+ -> cases 
    ]], { 
     cases = function(str) return (str:gsub('%a',function(a) return '['..a:lower()..a:upper()..']' end)) end 
     , bcases = function(str) return (str:gsub('%a',function(a) return a:lower()..a:upper() end)) end 
    }) 
    function iPattern(pattern,brackets) 
     ('sanity check'):find(pattern) 
     return table.concat({re.match(pattern, brackets and pb or p)}) 
    end 
end 

local test     = '[ab%c%]d%%]+ o%%r %bnm' 
print(iPattern(test))  -- [ab%c%]d%%]+ [oO]%%[rR] %bnm 
print(iPattern(test,true)) -- [aAbB%c%]dD%%]+ [oO]%%[rR] %bnm 
print(('qwe [%D]% O%r n---m asd'):match(iPattern(test, true))) -- %D]% O%r n---m 

versión pura Lua:

Es necesario analizar todos los caracteres de la cadena para convertirla en un patrón correcto porque los patrones Lua no tienen alternancias como en las expresiones regulares (abc | algo).

function iPattern(pattern, brackets) 
    ('sanity check'):find(pattern) 
    local tmp = {} 
    local i=1 
    while i <= #pattern do    -- 'for' don't let change counter 
     local char = pattern:sub(i,i) -- current char 
     if char == '%' then 
      tmp[#tmp+1] = char   -- add to tmp table 
      i=i+1      -- next char position 
      char = pattern:sub(i,i) 
      tmp[#tmp+1] = char 
      if char == 'b' then   -- '%bxy' - add next 2 chars 
       tmp[#tmp+1] = pattern:sub(i+1,i+2) 
       i=i+2 
      end 
     elseif char=='[' then   -- brackets 
      tmp[#tmp+1] = char 
      i = i+1 
      while i <= #pattern do 
       char = pattern:sub(i,i) 
       if char == '%' then  -- no '%bxy' inside brackets 
        tmp[#tmp+1] = char 
        tmp[#tmp+1] = pattern:sub(i+1,i+1) 
        i = i+1 
       elseif char:match("%a") then -- letter 
        tmp[#tmp+1] = not brackets and char or char:lower()..char:upper() 
       else       -- something else 
        tmp[#tmp+1] = char 
       end 
       if char==']' then break end -- close bracket 
       i = i+1 
      end 
     elseif char:match("%a") then -- letter 
      tmp[#tmp+1] = '['..char:lower()..char:upper()..']' 
     else 
      tmp[#tmp+1] = char   -- something else 
     end 
     i=i+1 
    end 
    return table.concat(tmp) 
end 

local test     = '[ab%c%]d%%]+ o%%r %bnm' 
print(iPattern(test))  -- [ab%c%]d%%]+ [oO]%%[rR] %bnm 
print(iPattern(test,true)) -- [aAbB%c%]dD%%]+ [oO]%%[rR] %bnm 
print(('qwe [%D]% O%r n---m asd'):match(iPattern(test, true))) -- %D]% O%r n---m 
+0

Bienvenido a stackoverflow. Las mejores respuestas generalmente no son solo de código. Explican el código, o donde el PO falló en sus intentos. –

Cuestiones relacionadas