Frontier Pattern

lua-users home
wiki

"Frontier"(边界)表达式模式 %f 是 Lua 中一个先前未公开的模式特性(有关其未公开的原因,请参阅 LuaList:2006-12/msg00536.html)。%f 允许匹配从一个不在字符集中的字符到另一个在字符集中的字符的转换。

功能上,它与 \b 正则表达式转义序列有类似的作用,允许“匹配”从一种字符集到另一种字符集的转换。

让我们考虑一个相当简单的任务:在字符串中查找所有大写单词。

第一次尝试:%u+

string.gsub ("the QUICK brown fox", "%u+", print)

QUICK

这看起来不错,找到了一个全大写的单词。但看看这个:

string.gsub ("the QUICK BROwn fox", "%u+", print)

QUICK
BRO

我们还找到了一个部分大写的单词。


第二次尝试:%u+%A

string.gsub ("the QUICK BROwn fox", "%u+%A", print)

QUICK

对非字母字符的检测正确地排除了部分大写的单词。但是等等!还有这个:

string.gsub ("the QUICK brOWN fox", "%u+%A", print)

QUICK 
OWN 

我们还有第二个问题。

string.gsub ("the QUICK. brown fox", "%u+%A", print)

QUICK.

单词后面的标点符号现在是捕获字符串的一部分,这是不想要的。

第三次尝试:%A%u+%A

string.gsub ("the QUICK brOWN FOx jumps", "%A%u+%A", print)

 QUICK

这可以正确地排除两个部分大写的单词,但仍然会包含标点符号,如下所示:

string.gsub ("the (QUICK) brOWN FOx jumps", "%A%u+%A", print)

(QUICK)

此外,除了捕获两端的非字母字符外,还有一个问题。看看这个:

string.gsub ("THE (QUICK) brOWN FOx JUMPS", "%A%u+%A", print)

(QUICK)

字符串开头和结尾的正确大写单词没有被检测到。

解决方案:Frontier Pattern:%f

string.gsub ("THE (QUICK) brOWN FOx JUMPS", "%f[%a]%u+%f[%A]", print)

THE
QUICK
JUMPS

Frontier Pattern %f 后跟一个集合,它检测从“不在集合中”到“在集合中”的转换。字符串边界被视为“不在集合中”,因此它也能匹配字符串开头要匹配的单词。

第二个 Frontier Pattern 也在字符串末尾匹配,因此我们的最后一个单词也被捕获了。

不使用 Frontier Pattern 的替代方案

不使用 Frontier Pattern,人们可能会诉诸于类似这样的方法:

s = "THE (QUICK) brOWN FOx JUMPS"
s = "\0" .. s:gsub("(%A)(%u)", "%1\0%2")
             :gsub("(%u)(%A)", "%1\0%2") .. "\0"
s = s:gsub("%z(%u+)%z", print)


--NickGammon
也许最好采用这种方法:
('_'..s..'_'):gsub('%A(%u+)%A', print)
--DmitryGaivoronsky

并非完全如此。

s = "THE QUICK brOWN FOx JUMPS"
('_'..s..'_'):gsub('%A(%u+)%A', print)
--> THE JUMPS

你可以这样做:

(' '..s..' '):gsub('%A+', '  '):gsub(' (%u+) ', print)
--> THE QUICK JUMPS

或者这样做:

s:gsub('%a+', ' %1 '):gsub(' (%u+) ', print)
--> THE QUICK JUMPS

该模式可以扩展到更一般的陈述:“查找所有至少四个字符长,并且全为小写或全为大写的单词”……

s = "THE QUICK brOWN FOx JUMPS over"
s:gsub('%a+', ' %1 ')      -- identify words with ' (%a+) '
                           -- (all following patterns match a subset of this)
 :gsub(' %u+%l+%a* ', '')  -- subtract mixed case words starting with upper
 :gsub(' %l+%u+%a* ', '')  -- subtract mixed case words starting with lower
 :gsub(' %a%a?%a? ', '')   -- subtract words with 1-3 characters
 :gsub(' (%a+) ', print)   -- extract words
--> QUICK JUMPS over
--DavidManura

我认为上面的例子在 lua lpeg re 中更快速、更易读。

s = "THE QUICK brOWN FOx JUMPS over"

= re.match(s, "(%A* ( {%u^+4 / %l^+4} (%A/!.) / %a+ ) )+")
QUICK   JUMPS   over
-- Albert Chan

RecentChanges · preferences
编辑 · 历史
最后编辑于 2024 年 1 月 25 日下午 2:51 GMT (diff)