2016-06-14 144 views
0

我是新來的「LPEG」和「重」的Lua的模塊,目前我想寫基於以下規則的模式:區分大小寫的匹配

  1. 比賽以「gv _ $/gv $/v $/v _ $/x $/xv $/dba_/all_/cdb_」開頭並且前綴「SYS。%s *」或「PUBLIC。%s *」的字符串爲可選
  2. 的字符串不應當遵循字母,即,該模式將不匹配「XSYS.DBA_OBJECTS」,因爲它遵循「X」
  3. 的模式是不區分大小寫

例如,下面的字符串應該匹配的模式:

,sys.dba_objects,  --should return "sys.dba_objects"  
SyS.Dba_OBJECTS 
cdb_objects 
dba_hist_snapshot)  --should return "dba_hist_snapshot" 

目前我的模式是下面這隻能滿足非字母數字+字符串大寫:

p=re.compile[[ 
     pattern <- %W {owner* name} 
     owner <- 'SYS.'/ 'PUBLIC.' 
     name <- {prefix %a%a (%w/"_"/"$"/"#")+} 
     prefix <- "GV_$"/"GV$"/"V_$"/"V$"/"DBA_"/"ALL_"/"CDB_" 
     ]] 
print(p:match(",SYS.DBA_OBJECTS")) 

我的問題是:

  1. 如何實現不區分大小寫的匹配?有一些關於解決方案的主題,但我太新瞭解
  2. 如何正確返回匹配的字符串,而不是也必須加上%W?例如Java中的「(?= ...)」

如果您能提供模式或相關功能,請高度讚賞。

回答

0

你可以試着調整這個語法

local re = require're' 

local p = re.compile[[ 
    pattern <- ((s? { <name> })/s/.)* !. 
    name <- (<owner> s? '.' s?)? <prefix> <ident> 
    owner <- (S Y S)/(P U B L I C) 
    prefix <- (G V '_'? '$')/(V '_'? '$')/(D B A '_')/(C D B '_') 
    ident <- [_$#%w]+ 
    s  <- (<comment>/%s)+ 
    comment <- '--' (!%nl .)* 
    A  <- [aA] 
    B  <- [bB] 
    C  <- [cC] 
    D  <- [dD] 
    G  <- [gG] 
    I  <- [iI] 
    L  <- [lL] 
    P  <- [pP] 
    S  <- [sS] 
    U  <- [uU] 
    V  <- [vV] 
    Y  <- [yY] 
    ]] 
local m = { p:match[[ 
,sys.dba_objects,  --should return "sys.dba_objects" 
SyS.Dba_OBJECTS 
cdb_objects 
dba_hist_snapshot)  --should return "dba_hist_snapshot" 
]] } 
print(unpack(m)) 

。 。 。打印匹配表m

sys.dba_objects SyS.Dba_OBJECTS cdb_objects  dba_hist_snapshot 

注意,不區分大小寫是非常難實現了詞法分析器所以每個字母都有獲得單獨的規則 - 你需要更多的這些最後。

這個語法把你的樣品中的意見,照顧和跳過它們與空白一起打完比賽「應該回歸」中不存在的輸出。

您可以使用prefixident規則來指定對象名稱中的其他前綴和允許的字符。

注:!.意味着檔案結尾。 !%nl表示「不是行尾」。 ! p& p正在構建非消費模式,即當前輸入指針在匹配時不會遞增(僅測試輸入)。

注2:printunpack -ing是一個總的黑客。

注3:這裏是一個tracable LPeg re可用於調試語法。通過truere.compile的第三參數獲得執行跟蹤測試/匹配/跳過行動對每個規則和訪問的位置。

+0

謝謝,這真的很酷。 – Tyler

0

最後,我得到了一個解決方案,但不是那麼優雅,這是將一個額外的參數case_insensitive添加到re.compile, re.find, re.match and re.gsub函數。當參數值是true,然後調用case_insensitive_pattern重寫模式:

... 
local fmt="[%s%s]" 
local function case_insensitive_pattern(quote,pattern) 
    -- find an optional '%' (group 1) followed by any character (group 2) 
    local stack={} 
    local is_letter=nil 
    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" 
       if is_letter==false then 
        stack[#stack]=stack[#stack]..percent .. letter 
       else 
        stack[#stack+1]=percent .. letter 
        is_letter=false 
       end 
      else 
       if is_letter==false then 
        stack[#stack]=quote..stack[#stack]..quote 
        is_letter=true 
       end 
       -- else, return a case-insensitive character class of the matched letter 
       stack[#stack+1]=fmt:format(letter:lower(), letter:upper()) 
      end 
      return "" 
     end) 
    if is_letter==false then 
     stack[#stack]=quote..stack[#stack]..quote 
    end 
    if #stack<2 then return stack[1] or (quote..pattern..quote) end 
    return '('..table.concat(stack,' ')..')' 
end 

local function compile (p, defs, case_insensitive) 
    if mm.type(p) == "pattern" then return p end -- already compiled 
    if case_insensitive==true then 
    p=p:gsub([[(['"'])([^\n]-)(%1)]],case_insensitive_pattern):gsub("%(%s*%((.-)%)%s*%)","(%1)") 
    end 
    local cp = pattern:match(p, 1, defs) 
    if not cp then error("incorrect pattern", 3) end 
    return cp 
end 
... 
相關問題