我正在尝试创建一个LPeg模式,以匹配UTF-8编码输入中的任何Unicode标点符号。我想出了Selene和LPeg的婚姻:
local unicode = require("unicode")
local lpeg = require("lpeg")
local punctuation = lpeg.Cmt(lpeg.Cs(any * any^-3), function(s,i,a)
local match = unicode.utf8.match(a, "^%p")
if match == nil
return false
else
return i+#match
end
end)这似乎有效,但它将忽略由几个Unicode代码点组合而成的标点符号(如果存在这些字符),因为我前面只读取了4个字节,这可能会降低解析器的性能,而且当我将包含一个矮小UTF-8字符的字符串提供给它时,它可能会破坏解析器的性能,而且当我给它一个包含一个矮小的UTF-8字符的字符串时(尽管它现在似乎正常工作)。
我想知道这是否一种正确的做法,还是有更好的方法来实现我正在努力实现的目标。
发布于 2016-08-18 07:18:43
在LPeg主页中的一个例子中显示了匹配UTF-8字符的正确方法。UTF-8字符的第一个字节决定了它的一部分还有多少字节:
local cont = lpeg.R("\128\191") -- continuation byte
local utf8 = lpeg.R("\0\127")
+ lpeg.R("\194\223") * cont
+ lpeg.R("\224\239") * cont * cont
+ lpeg.R("\240\244") * cont * cont * cont在此utf8模式的基础上,我们可以使用lpeg.Cmt和Selene match函数,就像您建议的那样:
local punctuation = lpeg.Cmt(lpeg.C(utf8), function (s, i, c)
if unicode.utf8.match(c, "%p") then
return i
end
end)注意,我们返回i,这与Cmt所期望的是一致的:
给定的函数作为参数获取整个主题,当前位置(在patt匹配之后),以及patt生成的任何捕获值。函数返回的第一个值定义了匹配的发生方式。如果调用返回一个数字,则匹配成功,并且返回的号码将成为新的当前位置。
这意味着我们应该返回函数接收的相同的数字,即在UTF-8字符之后的位置。
https://stackoverflow.com/questions/39006753
复制相似问题