在Lua中,我正在尝试模式匹配和捕获:
+384 Critical Strike (Reforged from Parry Chance)
Run Code Online (Sandbox Code Playgroud)
如
(+384) (Critical Strike)
Run Code Online (Sandbox Code Playgroud)
后缀(Reforged from %s)是可选的.
注意:在Lua中,他们不会将它们称为正则表达式,他们称之为模式,因为它们不是常规的.
示例字符串:
+384 Critical Strike
+1128 Hit
Run Code Online (Sandbox Code Playgroud)
这分为两部分我想捕获:

+384Critical Strike.我可以使用一个相当简单的模式捕获它们:

而这种模式在lua中起作用:
local text = "+384 Critical Strike";
local pattern = "([%+%-]%d+) (.+)";
local _, _, value, stat = strfind(text, pattern);
Run Code Online (Sandbox Code Playgroud)
+384 Critical Strike现在我需要扩展该正则表达式 模式以包含可选后缀:
+384 Critical Strike (Reforged from Parry Chance)
Run Code Online (Sandbox Code Playgroud)
其中细分为:

注意:我并不特别关心可选的尾随后缀; 这意味着我没有要求捕获它,虽然捕获它会很方便.
这是我开始陷入贪婪捕获问题的地方.我已经拥有的模式就是我不想要的:
([%+%-]%d+) (.+)+384Critical Strike (Reforged from Parry Chance)但是,让我们尝试在模式中包含后缀:

与模式:
pattern = "([%+%-]%d+) (.+)( %(Reforged from .+%))?"
Run Code Online (Sandbox Code Playgroud)
我正在使用?运算符来指示0或1出现后缀,但这些都没有匹配.
我盲目地尝试将可选后缀组从括号更改(为括号[:
pattern = "([%+%-]%d+) (.+)[ %(Reforged from .+%)]?"
Run Code Online (Sandbox Code Playgroud)
但现在比赛再次贪婪:
+384Critical Strike (Reforged from Parry Chance)基于Lua 模式参考):
- x :(其中x不是魔术字符之一^ $()%.[]*+ - ?)表示字符x本身.
- .:(一个点)代表所有字符.
- %a:代表所有字母.
- %c:表示所有控制字符.
- %d:代表所有数字.
- %l:表示全部小写字母.
- %p:表示所有标点字符.
- %s:表示所有空格字符.
- %u:表示全部大写字母.
- %w:代表所有字母数字字符.
- %x:表示所有十六进制数字.
- %z:表示具有表示0的字符.
- %x :(其中x是任何非字母数字字符)表示字符x.这是逃避魔法角色的标准方法.当用于在模式中表示自身时,任何标点符号(甚至是非魔法)都可以在前面加上'%'.
- [set]:表示集合中所有字符的并集的类.可以通过用" - "分隔范围的结束字符来指定一系列字符.上述所有类%x也可以用作集合中的组件.集合中的所有其他字符代表自己.例如,[%w_](或[_%w])表示所有字母数字字符加下划线,[0-7]表示八进制数字,[0-7%l% - ]表示八进制数字加上小写字母字母加上' - '字符.范围和类之间的交互未定义.因此,[%az]或[a - %%]等模式没有意义.
- [^ set]:表示set的补码,其中set如上所述.
对于由单个字母(%a,%c等)表示的所有类,相应的大写字母表示类的补码.例如,%S代表所有非空格字符.
字母,空格和其他字符组的定义取决于当前区域设置.特别是,类[az]可能不等于%l.
和魔法匹配者:
*,匹配类中0或更多重复的字符.这些重复项总是匹配最长的序列;+,匹配类中一个或多个重复的字符.这些重复项总是匹配最长的序列;-,它也匹配类中0或更多重复的字符.与'*'不同,这些重复项总是匹配最短的序列;?,匹配类中0或1次出现的字符;我注意到有一个贪婪的 *,非贪婪的 -修饰符.由于我的中间字符串匹配器:
(%d) (%s) (%s)
Run Code Online (Sandbox Code Playgroud)
似乎是在吸收文字直到最后,也许我应该试着让它变得非贪婪,通过改变*为-:
oldPattern = "([%+%-]%d+) (.*)[ %(Reforged from .+%)]?"
newPattern = "([%+%-]%d+) (.-)[ %(Reforged from .+%)]?"
Run Code Online (Sandbox Code Playgroud)
除了现在它不匹配:
+384而不是中间组捕获"任何"字符(即.),我尝试了一个包含所有内容的集合,除了 (:
pattern = "([%+%-]%d+) ([^%(]*)( %(Reforged from .+%))?"
Run Code Online (Sandbox Code Playgroud)
从那里车轮从货车上掉下来:
local pattern = "([%+%-]%d+) ([^%(]*)( %(Reforged from .+%))?"
local pattern = "([%+%-]%d+) ((^%()*)( %(Reforged from .+%))?"
local pattern = "([%+%-]%d+) (%a )+)[ %(Reforged from .+%)]?"
Run Code Online (Sandbox Code Playgroud)
我以为我很接近:
local pattern = "([%+%-]%d+) ([%a ]+)[ %(Reforged from .+%)]?"
Run Code Online (Sandbox Code Playgroud)
抓住了
- value = "+385"
- stat = "Critical Strike " (notice the trailing space)
Run Code Online (Sandbox Code Playgroud)
所以这就是我把头靠在枕头上去睡觉的地方; 我不敢相信我已经花了四个小时在这个正则表达式模式上.
@NicolBolas使用伪正则表达式语言定义的所有可能字符串的集合是:
+%d %s (Reforged from %s)
Run Code Online (Sandbox Code Playgroud)
哪里
如果我必须写一个显然试图做我想要的正则表达式:
\+\-\d+ [\w\s]+( \(Reforged from [\w\s]+\))?
Run Code Online (Sandbox Code Playgroud)
但是如果我不能很好地解释它,我可以给你几乎完整的所有价值清单,我可能会在野外遇到这些价值.
+123 Parry 正数,单个单词+123 Critical Strike 正数,两个字-123 Parry 负数,单个单词-123 Critical Strike 负数,两个字+123 Parry (Reforged from Dodge) 正数,单个单词,可选后缀以单个单词出现+123 Critical Strike (Reforged from Dodge) 正数,两个单词,可选后缀用两个单词表示-123 Parry (Reforged from Hit Chance) 负数,单个单词,可选后缀,带有两个单词-123 Critical Strike (Reforged from Hit Chance) 负数,两个单词,可选后缀,两个单词有奖金模式,这些模式似乎也很明显:
+1234 Critical Strike Chance 四位数字,三个字+12345 Mount and run speed increase 五位数,五个字+123456 Mount and run speed increase 六位数,五个字-1 MoUnT aNd RuN sPeEd InCrEaSe 一位数字,五个字-1 HiT (Reforged from CrItIcAl StRiKe ChAnCe) 负一位数字,一个单词,可选后缀,带3个单词虽然理想模式应该符合上述奖金的条目,它不具备对.
实际上,我试图解析的所有"数字"都将被本地化,例如:
+123,456 英文(en-US)+123.456 在德国(de-DE)+123'456 法语(fr-CA)+123 456 在爱沙尼亚语(et-EE)+1,23,456 在阿萨姆语(as-IN)任何答案都不得试图解释这些本地化问题.您不知道将显示数字的区域设置,这就是数字本地化已从问题中删除的原因.你必须严格假设的数字包含plus sign,hyphen minus和拉丁美洲的数字0通过9.我已经知道如何解析本地化的数字了.这个问题是关于尝试将可选后缀与贪婪模式解析器匹配.
编辑:你真的没有尝试处理本地化的数字.在某种程度上试图处理它们而不知道语言环境是错误的.例如,我没有包括所有可能的数字本地化.另一方面:我不知道未来可能存在哪些未来的本地化.
嗯,我没有安装Lua4,但这种模式在Lua5下工作.我希望它也适用于Lua4.
更新1:由于已经指定了其他要求(本地化),我已经调整了模式和测试以反映这些要求.
更新2:更新了模式和测试,以处理包含@IanBoyd在评论中提到的数字的其他类文本.添加了字符串模式的说明.
更新3:为问题的上次更新中提到的单独处理本地化数字的情况添加了变体.
尝试:
"(([%+%-][',%.%d%s]-[%d]+)%s*([%a]+[^%(^%)]+[%a]+)%s*(%(?[%a%s]*%)?))"
Run Code Online (Sandbox Code Playgroud)
或者(不尝试验证号码本地化令牌) - 只需在模式的末尾处取出不带字母数字的字母:
"(([%+%-][^%a]-[%d]+)%s*([%a]+[^%(^%)]+[%a]+)%s*(%(?[%a%s]*%)?))"
Run Code Online (Sandbox Code Playgroud)
上述两种模式都不是为了处理科学记数法中的数字(例如:1.23e + 10)
Lua5测试(编辑清理 - 测试变得混乱):
function test(tab, pattern)
for i,v in ipairs(tab) do
local f1, f2, f3, f4 = v:match(pattern)
print(string.format("Test{%d} - Whole:{%s}\nFirst:{%s}\nSecond:{%s}\nThird:{%s}\n",i, f1, f2, f3, f4))
end
end
local pattern = "(([%+%-][',%.%d%s]-[%d]+)%s*([%a]+[^%(^%)]+[%a]+)%s*(%(?[%a%s]*%)?))"
local testing = {"+123 Parry",
"+123 Critical Strike",
"-123 Parry",
"-123 Critical Strike",
"+123 Parry (Reforged from Dodge)",
"+123 Critical Strike (Reforged from Dodge)",
"-123 Parry (Reforged from Hit Chance)",
"-123 Critical Strike (Reforged from Hit Chance)",
"+122384 Critical Strike (Reforged from parry chance)",
"+384 Critical Strike ",
"+384Critical Strike (Reforged from parry chance)",
"+1234 Critical Strike Chance (Reforged from CrItIcAl StRiKe ChAnCe)",
"+12345 Mount and run speed increase (Reforged from CrItIcAl StRiKe ChAnCe)",
"+123456 Mount and run speed increase (Reforged from CrItIcAl StRiKe ChAnCe)",
"-1 MoUnT aNd RuN sPeEd InCrEaSe (Reforged from CrItIcAl StRiKe ChAnCe)",
"-1 HiT (Reforged from CrItIcAl StRiKe ChAnCe)",
"+123,456 +1234 Critical Strike Chance (Reforged from CrItIcAl StRiKe ChAnCe)",
"+123.456 Critical Strike Chance (Reforged from CrItIcAl StRiKe ChAnCe)",
"+123'456 Critical Strike Chance (Reforged from CrItIcAl StRiKe ChAnCe)",
"+123 456 Critical Strike Chance (Reforged from CrItIcAl StRiKe ChAnCe)",
"+1,23,456 Critical Strike Chance (Reforged from CrItIcAl StRiKe ChAnCe)",
"+9 mana every 5 sec",
"-9 mana every 20 min (Does not occurr in data but gets captured if there)"}
test(testing, pattern)
Run Code Online (Sandbox Code Playgroud)
这是模式的细分:
local explainPattern =
"(" -- start whole string capture
..
--[[
capture localized number with sign -
take at first as few digits and separators as you can
ensuring the capture ends with at least 1 digit
(the last digit is our sentinel enforcing the boundary)]]
"([%+%-][',%.%d%s]-[%d]+)"
..
--[[
gobble as much space as you can]]
"%s*"
..
--[[
capture start with letters, followed by anything which is not a bracket
ending with at least 1 letter]]
"([%a]+[^%(^%)]+[%a]+)"
..
--[[
gobble as much space as you can]]
"%s*"
..
--[[
capture an optional bracket
followed by 0 or more letters and spaces
ending with an optional bracket]]
"(%(?[%a%s]*%)?)"
..
")" -- end whole string capture
Run Code Online (Sandbox Code Playgroud)