2012-07-09 18 views
8

Piszę narzędzie grep w Lua dla naszych urządzeń mobilnych z systemem Windows CE 6/7, ale mam pewne problemy z wprowadzaniem wzorców dopasowania niewrażliwych na wielkość znaków. Oczywiste rozwiązanie konwersji wszystkiego na wielkie (lub niższe) nie działa tak po prostu ze względu na klasy znaków.Rozróżnianie wielkości liter Lua

Jedyne, co mogę wymyślić, to przekształcenie literałów w sam wzór na wielkie litery.

Oto co mam do tej pory:

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 

Nienawidzę przyznać, jak długo zajęło się jeszcze tak daleko, a ja wciąż widzę od razu tam będą problemy z rzeczy, jak uciekł procent znaki "%%"

Pomyślałem, że to dość powszechny problem, ale nie mogę znaleźć wiele na ten temat. Czy są jakieś łatwiejsze (lub przynajmniej kompletne) sposoby, aby to zrobić? Zaczynam szaleć tutaj ... Mam nadzieję, że wy, guru Lua, możecie mnie oświecić!

Odpowiedz

9

spróbować czegoś takiego:

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

która drukuje:

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

Awesome. Rysowałem puste miejsce. BTW: możesz powiedzieć 'wzór: gsub' tak jak powiedziałeś' letter: lower'. Możesz nawet powiedzieć '('[% s% s]'): format' ale to trochę dziwniejsze. – Mud

+0

Tak, 'string.format (...)' wygląda lepiej niż '('[% s% s]'): format (...)', ale podoba mi się 'wzorzec: gsub (...) 'lepiej! Dzięki. –

+0

Niewiarygodne. Ale jedno pytanie ... Jak to nie przekształcić czegoś takiego jak '%% test' na' %% [tT] est'? Czy to dopasowanie zostało pominięte, ponieważ poprzednia iteracja pasowałaby do "%%"? Może mój mózg jest dziś trochę smażony:/ – 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 

Czysta wersja Lua:

Konieczne jest przeanalizowanie wszystkich znaków w łańcuchu znaków w celu przekonwertowania go na poprawny wzorzec, ponieważ wzorce Lua nie mają alternatyw, jak w regexps (abc | something).

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

Witamy w stackoverflow. Najlepsze odpowiedzi zwykle nie są jedynie kodem. Wyjaśniają kod lub miejsce, w którym OP popełnił błąd w swoich próbach. –

Powiązane problemy