边界模式

lua-users home
wiki

“边界”表达式模式 **%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)

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

解决方案:边界模式:%f

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

THE
QUICK
JUMPS

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

第二个边界模式也在字符串末尾匹配,因此我们的最后一个单词也被捕获。

没有边界模式的替代方案

如果没有边界模式,人们可能会诉诸于以下方法

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

最近更改 · 偏好设置
编辑 · 历史记录
最后编辑于 2024 年 1 月 25 日下午 8:51 GMT (差异)