我的环境:
os
和其他几个允许访问本机文件系统,shell命令或类似内容的软件包,因此必须实现所有功能在Lua本身中(仅限)。我需要编写一个函数,如果输入字符串匹配任意字母和数字序列作为一个整个单词,则该函数返回true
,该单词重复一次或多次,并且可能带有标点符号在整个匹配子字符串的开头或结尾。我使用的是“整个单词”,其含义与PCRE单词边界\b
相同。
为了证明这个想法,这是使用LuLpeg的re
模块的不正确尝试;似乎可以使用否定的前瞻功能,但不能消除否定的外观后面:
function containsRepeatingWholeWord(input, word)
return re.match(input:gsub('[%a%p]+', ' %1 '), '%s*[^%s]^0{"' .. word .. '"}+[^%s]^0%s*') ~= nil
end
以下是示例字符串和预期的返回值(引号是句法的,就像键入Lua解释器一样,而不是字符串的文字部分;这样做是为了使尾部/前导空格显而易见):
" one !tvtvtv! two"
,单词: tv
,返回值: true
"I'd"
,单词: d
,返回值: false
"tv"
,单词: tv
,返回值: true
" tvtv! "
,单词: tv
,返回值: true
" epon "
,单词: nope
,返回值: false
" eponnope "
,单词: nope
,返回值: false
"atv"
,单词: tv
,返回值: false
如果我拥有完整的PCRE正则表达式库,则可以快速完成此操作,但我不能这样做,因为我无法链接到C,而且我还没有发现PCRE或类似的任何纯粹Lua实现。
我不确定LPEG是否足够灵活(直接使用LPEG或通过其re
模块使用)来完成我想做的事情,但是我很确定内置的Lua函数不能做我想做的事情我想要,因为它无法处理重复的字符序列。 (tv)+
不适用于Lua内置的string:match
功能和类似功能。
我一直在寻找有趣的资源,试图弄清楚该怎么做,但无济于事:
答案 0 :(得分:3)
我认为该模式不能可靠地工作,因为%s*[^%s]^0
部分匹配了一系列可选的空格字符,后跟非空格字符,然后它尝试匹配重复的单词,但失败了。之后,它不会在字符串中向后或向前移动,而是尝试在另一个位置匹配重复的单词。 LPeg和re
的语义与大多数正则表达式引擎的语义非常不同,即使对于看起来相似的事物也是如此。
这是基于re
的版本。该模式具有单个捕获(重复的单词),因此,如果找到重复的单词,则匹配返回字符串而不是数字。
function f(str, word)
local patt = re.compile([[
match_global <- repeated / ( [%s%p] repeated / . )+
repeated <- { %word+ } (&[%s%p] / !.) ]],
{ word = word })
return type(patt:match(str)) == 'string'
end
这有点复杂,因为香草re
无法生成lpeg.B
模式。
以下是使用lpeg
的{{1}}版本。 LuLPeg也可以在这里工作。
lpeg.B
答案 1 :(得分:2)
Lua模式足够强大。
此处不需要LPEG。
这是你的功能
function f(input, word)
return (" "..input:gsub(word:gsub("%%", "%%%%"), "\0").." "):find"%s%p*%z+%p*%s" ~= nil
end
这是对该功能的测试
for _, t in ipairs{
{input = " one !tvtvtv! two", word = "tv", return_value = true},
{input = "I'd", word = "d", return_value = false},
{input = "tv", word = "tv", return_value = true},
{input = " tvtv! ", word = "tv", return_value = true},
{input = " epon ", word = "nope", return_value = false},
{input = " eponnope ", word = "nope", return_value = false},
{input = "atv", word = "tv", return_value = false},
} do
assert(f(t.input, t.word) == t.return_value)
end