2012-07-09 4 views
8

Ich schreibe ein grep-Dienstprogramm in Lua für unsere mobilen Geräte mit Windows CE 6/7, aber ich bin auf einige Probleme mit der Implementierung von Groß-und Kleinschreibung nicht übereinstimmen. Die offensichtliche Lösung, alles in Großbuchstaben (oder niedriger) zu konvertieren, funktioniert aufgrund der Zeichenklassen nicht so einfach.Case-insensitive Lua pattern-matching

Die einzige andere Sache, die ich denken kann, wandelt die Literale in das Muster selbst in Großbuchstaben.

Hier ist, was ich bisher:

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 

Ich hasse es zuzugeben, wie lange sogar so weit kommen nahm, und ich kann immer noch sofort sehen, es werden Probleme mit Dingen wie entkam Prozent sein Zeichen '%%'

Ich dachte, das muss ein ziemlich häufiges Problem sein, aber ich kann nicht viel zu dem Thema finden. Gibt es leichtere (oder zumindest vollständige) Möglichkeiten, dies zu tun? Ich fange an, hier verrückt zu werden ... In der Hoffnung, dass Lua-Gurus da draußen mich erleuchten können!

Antwort

9

versuchen, etwas wie folgt aus:

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")) 

die druckt:

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

Ehrfürchtig. Ich zeichnete eine Lücke. BTW: Du kannst 'pattern: gsub' genauso sagen wie' 'letter: lower''. Man könnte sogar sagen "('[% s% s]'): format ', aber das ist ein wenig seltsamer. – Mud

+0

Ja, 'string.format (...)' sieht besser aus als '('[% s% s]'): format (...)', aber ich mag das 'pattern: gsub (...) "Besser! Vielen Dank. –

+0

Unglaublich. Aber eine Frage ... Wie konvertiert das nicht etwas wie "%% test" in "%% [tT] est"? Wird diese Übereinstimmung übersprungen, weil die vorherige Iteration mit '%%' übereinstimmt? Vielleicht ist mein Gehirn heute nur ein wenig gebraten:/ – 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 

Reine Lua-Version:

Es ist notwendig, alle Zeichen in der Zeichenfolge zu analysieren, um sie in ein korrektes Muster zu konvertieren, da Lua-Muster keine Änderungen wie in regexps (abc | something) haben.

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

Willkommen bei stackoverflow. Die besten Antworten sind normalerweise nicht nur Code. Sie erklären den Code oder wo das OP bei ihren Versuchen schief gelaufen ist. –