【发布时间】:2012-11-17 03:18:12
【问题描述】:
在 Lua 中,我正在尝试模式匹配和捕获:
+384 Critical Strike (Reforged from Parry Chance)
作为
(+384) (Critical Strike)
其中后缀 (Reforged from %s) 是可选的。
加长版
我正在尝试匹配 Lua using patterns (i.e. strfind) 中的字符串
注意:在 Lua 中,他们不称它们为正则表达式,而是称它们为模式,因为它们不是regular。
示例字符串:
+384 Critical Strike
+1128 Hit
这分为我要捕获的两个部分:
-
数字,带有前导的正或负指示符;他的情况是
+384 -
字符串,在本例中为
Critical Strike。
我可以使用相当简单的模式来捕捉这些:
这种模式在 lua 中有效:
local text = "+384 Critical Strike";
local pattern = "([%+%-]%d+) (.+)";
local _, _, value, stat = strfind(text, pattern);
- 值 =
+384 - 统计 =
Critical Strike
棘手的部分
Now 我需要扩展那个正则表达式 pattern 以包含一个可选 后缀:
+384 Critical Strike (Reforged from Parry Chance)
分为:
注意:我不特别关心可选的尾随后缀;这意味着我没有要求来捕捉它,虽然捕捉它会很方便。
这就是我开始解决贪婪捕获问题的地方。我已经拥有的模式立即做了我不希望它做的事情:
- 模式 =
([%+%-]%d+) (.+) - 值 =
+384 - 统计 =
Critical Strike (Reforged from Parry Chance)
但是让我们尝试在模式中包含后缀:
与模式:
pattern = "([%+%-]%d+) (.+)( %(Reforged from .+%))?"
我使用? 运算符来指示后缀的0 或1 出现但匹配nothing。
我盲目地尝试将可选的后缀组从括号(更改为括号[:
pattern = "([%+%-]%d+) (.+)[ %(Reforged from .+%)]?"
但现在比赛又贪心了:
- 值 =
+384 - 统计 =
Critical Strike (Reforged from Parry Chance)
- 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%-]表示八进制数字加小写字母加上“-”字符。 范围和类之间的交互没有定义。因此,像 [%a-z] 或 [a-%%] 这样的模式没有意义。
- [^set]:表示set的补集,其中set的解释如上。
对于所有由单个字母(%a、%c等)表示的类,对应的大写字母代表类的补码。例如,%S 代表所有非空格字符。
字母、空格和其他字符组的定义取决于当前的语言环境。特别是,[a-z] 类可能不等同于 %l。
还有魔法匹配器:
-
*,匹配类中 0 个或多个重复字符。这些重复项将始终匹配可能的最长序列; -
+,匹配类中的 1 个或多个重复字符。这些重复项将始终匹配可能的最长序列; -
-,也匹配类中 0 个或多个重复字符。与 '*' 不同,这些重复项将始终匹配最短的可能序列; -
?,匹配类中出现的 0 或 1 个字符;
我注意到有一个 greedy * 和一个 non-greedy - 修饰符。由于我的中间字符串匹配器:
(%d) (%s) (%s)
似乎一直在吸收文本,也许我应该尝试通过将 * 更改为 - 来使其不贪婪:
oldPattern = "([%+%-]%d+) (.*)[ %(Reforged from .+%)]?"
newPattern = "([%+%-]%d+) (.-)[ %(Reforged from .+%)]?"
除了现在不匹配:
- 值 =
+384 - 统计 = 无
而不是中间组捕获“任何”字符(即.),我尝试了一个包含所有内容的集合除了 (:
pattern = "([%+%-]%d+) ([^%(]*)( %(Reforged from .+%))?"
然后车轮从马车上脱落:
local pattern = "([%+%-]%d+) ([^%(]*)( %(Reforged from .+%))?"
local pattern = "([%+%-]%d+) ((^%()*)( %(Reforged from .+%))?"
local pattern = "([%+%-]%d+) (%a )+)[ %(Reforged from .+%)]?"
我以为我很接近:
local pattern = "([%+%-]%d+) ([%a ]+)[ %(Reforged from .+%)]?"
捕获
- value = "+385"
- stat = "Critical Strike " (notice the trailing space)
所以这就是我用头撞枕头睡觉的地方;我不敢相信我在这个正则表达式上花了四个小时......模式。
@NicolBolas 使用伪正则表达式语言定义的所有可能字符串的集合是:
+%d %s (Reforged from %s)
在哪里
-
+代表Plus Sign (+) 或"Minus Sign" (-) -
%d代表任何拉丁数字字符(例如0..9) -
%s代表任何拉丁文大写或小写字母,或嵌入的空格(例如A-Za-z) - 其余字符为文字。
如果我必须编写一个明显试图做我想做的事情的正则表达式:
\+\-\d+ [\w\s]+( \(Reforged from [\w\s]+\))?
但如果我解释得不够清楚,我可以给你几乎完整的列表,列出我在野外可能遇到的所有价值观。
-
+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)负数,两个单词,可选的后缀出现两个单词
有 bonus 模式,很明显这些模式也会匹配:
-
+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。我已经知道如何解析本地化数字。这个问题是关于尝试将可选后缀与贪婪模式解析器匹配。
编辑:您真的不必尝试处理本地化号码。在某种程度上试图在不知道语言环境的情况下处理它们是错误的。例如,我没有包括所有可能的数字本地化。另一方面:我不知道未来可能存在哪些本地化。
【问题讨论】:
-
很难提供答案,因为您似乎没有描述所有可能的字符串。
-
函数
strfind来自旧版Lua 4.0。你真的在使用那个旧版本吗? -
@prapin 从文字内容来看,这是魔兽世界中的Lua,也就是Lua 5.1。
strfind可能只是strfind = string.find。
标签: lua