【问题标题】:LPeg Pattern which matches strings without consecutive hypens匹配没有连续连字符的字符串的 LPg 模式
【发布时间】:2017-03-04 13:16:17
【问题描述】:

我正在尝试编写一个 LPeg 模式来匹配以下字符串:

  • 以字母开头
  • 之后包含字母数字字符
  • 不包含两个或多个连续的连字符(例如不允许test--string

作为参考,正则表达式 [a-zA-Z](-?[a-zA-Z0-9])* 匹配我要查找的内容。

这是我正在使用的代码,供参考:

require "lpeg"
P,R,C = lpeg.P,lpeg.R,lpeg.C

dash  = P"-"
ucase  = R"AZ"
lcase  = R"az"
digit  = R"09"
letter = ucase + lcase
alphanum = letter + digit

str_match = C(letter * ((dash^-1) * alphanum)^0)

strs = {
    "1too",
    "too0",
    "t-t-t",
    "t-t--t",
    "t--t-t",
    "t-1-t",
    "t--t",
    "t-one1",
    "1-1",
    "t-1",
    "t",
    "tt",
    "t1",
    "1",
}

for _,v in ipairs(strs) do
    if lpeg.match(str_match,v) ~= nil then
        print(v," => match!")
    else
        print(v," => no match")
    end
end

然而,令我沮丧的是,我得到以下输出:

1too     => no match
too0     => match!
t-t-t    => match!
t-t--t   => match!
t--t-t   => match!
t-1-t    => match!
t--t     => match!
t-one1   => match!
1-1      => no match
t-1      => match!
t        => match!
tt       => match!
t1       => match!
1        => no match

尽管代码输出了什么,t-t--tt--t-tt--t 不应该匹配。

【问题讨论】:

  • 仔细看看((dash^-1) * alphanum)^0!您说“将最多一个破折号后面紧跟一个字母数字的可能性分组,这一切都可能发生 0 次或更多次。”。因此,您的模式可能会在开头字母处失败。

标签: lua lpeg


【解决方案1】:

在您的模式letter * ((dash^-1) * alphanum)^0 中,lpeg 将尝试匹配字符串的前缀。对于您没想到会匹配的情况

t-t--t
t--t-t
t--t

以粗体突出显示的部分是您的模式成功匹配的部分。 lpeg.match 返回最后一个位置(它是一个数字),如果没有捕获到,它能够解析到使用您的模式。对于上述 3 种情况,系统会捕获匹配的子部分来解释您看到的错误输出。

如果您只是一次匹配每个字符串,则可以修改模式以检查解析后是否没有剩余字符。

str_match = C(letter * ((dash^-1) * alphanum)^0) * -1

同样使用lpeg.re模块

re_pat = re.compile "{ %a ('-'? %w)* } !."

对于流匹配或查找目标字符串中的所有模式出现,像这样将语法规则堆叠在一起

stream_parse = re.compile
[[
  stream_match  <- ((str_match / skip_nonmatch) delim)* str_match?
  str_match     <- { %a ('-'? %w)* } (&delim / !.)
  skip_nonmatch <- !str_match (!delim .)*

  delim         <- %s+
]]

任何匹配项都会被捕获并返回。如果没有匹配项,您将返回 nil 或指示模式在字符串中停止解析的位置的数字。

编辑:对于需要解析在不匹配时返回 nil 的情况,对语法的这种调整应该可以解决问题

stream_parse = re.compile
[[
  stream_match  <- (str_match / skip_nonmatch+ &str_match)+
  str_match     <- { %a ('-'? %w)* } (&delim / !.)
  skip_nonmatch <- !str_match (!delim .)* delim

  delim         <- %s+
]]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-28
    • 1970-01-01
    相关资源
    最近更新 更多