贪婪/非贪婪模式匹配和在Lua可选后缀(Greedy/Non-Greedy pattern matc

2019-08-03 07:51发布

在Lua中,我试图模式匹配和捕捉:

+384 Critical Strike (Reforged from Parry Chance)

(+384) (Critical Strike)

其中后缀(Reforged from %s)是可选的。

长版

我想匹配的字符串使用模式的Lua(即strfind

:在Lua中,他们不叫他们正则表达式 ,他们称他们的模式 ,因为他们不是正规 。

例如字符串:

+384 Critical Strike
+1128 Hit

这被分解成两个部分,我想捕捉:

  • 数量 ,与领先的正或负的指示符; INT他的案件是+384
  • 字符串 ,在这种情况下是Critical Strike

我可以用一个相当简单的方式捕捉这些:

而这种模式在Lua工作:

local text = "+384 Critical Strike";
local pattern = "([%+%-]%d+) (.+)";
local _, _, value, stat = strfind(text, pattern);
  • 值= +384
  • STAT = Critical Strike

棘手的问题

现在我需要展开正则表达式 模式包括一个可选的后缀:

+384 Critical Strike (Reforged from Parry Chance)

这是细分为:

注:我并不特别在意可选尾随后缀; 这意味着我并没有需要捕捉到它,虽然捕捉这将是得心应手。

这是我开始变得与贪婪捕捉的问题。 马上我已经有图案做什么,我不希望它:

  • 图案= ([%+%-]%d+) (.+)
  • 值= +384
  • STAT = Critical Strike (Reforged from Parry Chance)

但是,让我们尝试在模式中包含的后缀:

与图案:

pattern = "([%+%-]%d+) (.+)( %(Reforged from .+%))?"

而我使用的? 运营商表示01后缀的外观,但没有什么比赛。

盲目地试图改变从括号中的可选的后缀组(以括号[

pattern = "([%+%-]%d+) (.+)[ %(Reforged from .+%)]?"

但现在的比赛是贪婪的一次:

  • 值= +384
  • STAT = Critical Strike (Reforged from Parry Chance)

基于所述的Lua 图案参考 ):

  • X:(?其中x是不是神奇的字符^ $()%一个[] * + - )代表字符x本身。
  • :(点)代表所有的字符。
  • %A:代表所有字母。
  • %C:表示所有的控制字符。
  • %d:代表所有的数字。
  • %L:代表所有小写字母。
  • %P:代表所有的标点字符。
  • %S:代表所有空格字符。
  • %u:代表所有大写字母。
  • %(重量):代表所有字母数字字符。
  • %x:表示所有十六进制数字。
  • %Z:表示与表示0的字符。
  • %×:(其中x是任何非字母数字字符)表示字符x。 这是为了躲避魔法字符的标准方式。 任何标点字符(即使非魔法)可以由“%”用来表示本身的图案时之前。
  • [组]:表示的类,这是在集中的所有字符的联合。 “ - ”字符的范围可以通过分离用该范围的结束字符指定。 上述所有类%×也可以用作组构件。 在集合中的所有其它字符代表自己。 例如,[%W_](或[_%(重量))表示所有字母数字字符加下划线,[0-7]表示的八进制数字,和[0-7%1% - ]表示八进制数字加小写字母加上“ - ”字符。 不限定范围和类之间的相互作用。 因此,图案等[%AZ]或[A - %%]没有意义。
  • [^组]:表示集合,其中组被解释为上述的补码。

对于由单个字母(%A,%C等)代表的所有类,相应的大写字母表示的类的补充。 例如,%S代表所有非空格字符。

信,空间等字符组的定义取决于当前的语言环境。 特别地,所述类[AZ]可能不等同于%升。

和魔术的匹配:

  • * ,它匹配的字符的0或多次重复中的类。 这些重复的项目总是会匹配最长可能的序列;
  • + ,它匹配的字符的1次或多次重复中的类。 这些重复的项目总是会匹配最长可能的序列;
  • -其也匹配字符的0或多次重复中的类。 不像“*”,这些重复的项目将始终与最短的序列;
  • ? ,它匹配0或1起发生在类的字符;

我注意到,有一个贪婪的 *非贪婪 -修改。 由于我的中间字符串匹配:

(%d) (%s) (%s)

似乎是吸收的文本,直到最后,也许我应该尽量做到不贪婪 ,通过改变*-

oldPattern = "([%+%-]%d+) (.*)[ %(Reforged from .+%)]?"
newPattern = "([%+%-]%d+) (.-)[ %(Reforged from .+%)]?"

除了现在它不匹配:

  • 值= +384
  • STAT =

而不是中间组捕获中“任何”字符(即. ,我试过了一组包含了一切) (

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)

哪里

  • +表示无论是加号( + )或“减号”( -
  • %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) 负数,两个字,可选后缀本两个字

奖金的模式它似乎很明显,模式也将匹配:

  • +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 signhyphen minus ,和拉丁美洲数字09 。 我已经知道如何解析本地化数字。 这个问题是关于试图匹配与贪婪模式解析器可选的后缀。

编辑 :你真的没有尝试处理本地化的数字。 在一定程度上试图处理他们,不知道的语言环境,是错误的。 举例来说,我不包括数字的所有可能的本地化。 对于另:我不知道什么样的未来本地化将来可能存在的。

Answer 1:

嗯,我没有安装Lua4但Lua5下,这种模式的工作原理。 我希望它为Lua4正常工作。

更新1:由于额外的要求已经指定(本地化)我已经适应模式和测试,以反映这些。

更新2:更新模式和测试,以应付额外的类包含一些由@IanBoyd在评论中提到的文本。 添加字符串模式的解释。

更新3:增加了对地方在上更新的问题中提到的本地化号码分开处理的情况变化。

尝试:

"(([%+%-][',%.%d%s]-[%d]+)%s*([%a]+[^%(^%)]+[%a]+)%s*(%(?[%a%s]*%)?))"

或(不尝试验证号码定位令牌) - 刚刚采取任何这是不符合的模式结束一个数字哨兵的一封信:

"(([%+%-][^%a]-[%d]+)%s*([%a]+[^%(^%)]+[%a]+)%s*(%(?[%a%s]*%)?))"

无论是上面的图案是为了应对科学记数法表示的(如: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)

下面是模式的细分:

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


Answer 2:

为什么在一个模式解析这个时候,你可以使用几种?

首先,获得数:

local num, rest = string.match(test_string, "([%+%-]?%d+)%S*(.+)")

然后使该枚举命中类型的可能性的表。

local hitTypes =
{
  "Hit",
  "Critical Strike",
  -- Insert more.
}

现在,遍历列表,测试针对每一个。

local hitIndex = nil
local reforge = nil

for i, htype in ipairs(hitTypes) do
  local final = string.match(rest, htype .. "%S*(.*)")
  if(final) then
    hitIndex = i
    reforge = string.match(final, "%(Reforged from (.+)%)")
  end
end

Lua的图案是有限的,所以最好用实际的代码来避免其局限性。



Answer 3:

这是更简单,而不是只匹配模式,可以直接查找短输出到你需要的字符串,你可以用它string.gsub

例:

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)"}

for k,v in ipairs(testing) do
  local result = string.gsub(v, "([%+%-][',%.%d%s]-[%+%d]+)%s*([%a]+[^%(^%)]+[%a]+)%s*(%(?[%a%s]*%)?)", '(%1) (%2) %3')
  print(result)
end

产量

 (+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) (+384) (Critical 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) 


Answer 4:

function match_some_stat_thing(str)
    local sign, amount, label, note = string.match(str.."()", "^([%+%-])(%d+) ([%a ]-) ?(%b())")
    return sign == "+" and amount or -amount, label, string.match(note, "%((.*)%)")
end
print(string.format("%d %q %q", match_some_stat_thing("+384 Critical Strike (Reforged from Parry Chance)")))
print(string.format("%d %q %q", match_some_stat_thing("+384 Critical Strike")))
print(string.format("%d %q %q", match_some_stat_thing("+384 Critical Strike ")))

不是一个单一的模式,但它的工作原理。



文章来源: Greedy/Non-Greedy pattern matching and optional suffixes in Lua
标签: lua