17

Luaでは、パターンマッチングとキャプチャを試みています。

+384 Critical Strike (Reforged from Parry Chance)

なので

(+384) (Critical Strike)

ここで、接尾辞(Reforged from %s)はオプションです。

ロングバージョン

パターンを使用してLuaの文字列を照合しようとしています(つまりstrfind

:Luaでは、正規表現とは呼ばれません。正規表現ではないため、パターンと呼ばれます。

文字列の例:

+384 Critical Strike
+1128 Hit

これは、キャプチャしたい2つの部分に分けられます。

ここに画像の説明を入力してください

  • 数字、先頭に正または負のインジケーターが付いています。彼の場合は+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 .+%))?"

そして、私は接尾辞の出現?を示すために演算子を使用していますが、0それは何にも一致しません1

オプションのサフィックスグループをかっこから角かっこに変更しようとしまし([

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

しかし今、試合は再び貪欲です:

  • 値=+384
  • stat =Critical Strike (Reforged from Parry Chance)

Luaパターンリファレンスに基づく):

  • x :(ここでxは魔法の文字の1つではありません^$()%。[] * +-?)は文字x自体を表します。
  • :(ドット)はすべての文字を表します。
  • %a:すべての文字を表します。
  • %c:すべての制御文字を表します。
  • %d:すべての桁を表します。
  • %l:すべて小文字を表します。
  • %p:すべての句読文字を表します。
  • %s:すべてのスペース文字を表します。
  • %u:すべて大文字を表します。
  • %w:すべての英数字を表します。
  • %x:すべての16進数を表します。
  • %z:表現0の文字を表します。
  • %x:(xは英数字以外の文字)は文字xを表します。これは魔法のキャラクターを逃れるための標準的な方法です。パターンでそれ自体を表すために使用される場合、句読文字(非魔法であっても)の前に「%」を付けることができます。
  • [set]:セット内のすべての文字の和集合であるクラスを表します。文字の範囲は、範囲の終了文字を「-」で区切ることによって指定できます。上記のすべてのクラス%xは、セット内のコンポーネントとしても使用できます。セット内の他のすべての文字は、それ自体を表します。たとえば、[%w _](または[_%w])はすべての英数字とアンダースコアを表し、[0-7]は8進数を表し、[0-7%l%-]は8進数と小文字を表します。文字と「-」文字。範囲とクラス間の相互作用は定義されていません。したがって、[%az]や[a-%%]のようなパターンには意味がありません。
  • [^ set]:setの補集合を表します。ここで、setは上記のように解釈されます。

単一文字(%a、%cなど)で表されるすべてのクラスの場合、対応する大文字はクラスの補集合を表します。たとえば、%Sはすべての非スペース文字を表します。

文字、スペース、およびその他の文字グループの定義は、現在のロケールによって異なります。特に、クラス[az]は%lと同等ではない場合があります。

と魔法のマッチャー:

  • *、クラス内の文字の0回以上の繰り返しに一致します。これらの繰り返し項目は、常に可能な限り長いシーケンスに一致します。
  • +、クラス内の文字の1回以上の繰り返しに一致します。これらの繰り返し項目は、常に可能な限り長いシーケンスに一致します。
  • -、これは、クラス内の0回以上の文字の繰り返しにも一致します。'*'とは異なり、これらの繰り返し項目は常に可能な限り短いシーケンスに一致します。
  • ?、クラス内の文字の0または1回の出現に一致します。

欲張りな修飾子と欲張りでない修飾 *子があることに気づきました。私のミドルストリングマッチャー以来: -

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

最後までテキストを吸収しているようです。おそらく、を:に変更して、貪欲でないようにする必要があります。*-

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

今を除いて、それは一致しません:

  • 値=+384
  • stat = nil

中間グループが「任意の」文字(つまり)をキャプチャするのではなく、以下を除く.すべてを含むセットを試しました。 (

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)

だから、これは私が枕に頭をぶつけて寝るところです。この正規表現に4時間を費やしたなんて信じられません...パターン


@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 正の数、2つの単語
  • -123 Parry 負の数、一言
  • -123 Critical Strike 負の数、2ワード
  • +123 Parry (Reforged from Dodge) 正の数、単一の単語、単一の単語に存在するオプションの接尾辞
  • +123 Critical Strike (Reforged from Dodge) 正の数、2語、2語のオプションの接尾辞
  • -123 Parry (Reforged from Hit Chance) 負の数、1つの単語、2つの単語を含むオプションの接尾辞
  • -123 Critical Strike (Reforged from Hit Chance) 負の数、2語、2語のオプションの接尾辞

ボーナスパターンがあり、パターンも一致することは明らかです。

  • +1234 Critical Strike Chance 4桁の数字、3つの単語
  • +12345 Mount and run speed increase 5桁の数字、5つの単語
  • +123456 Mount and run speed increase 6桁の数字、5つの単語
  • -1 MoUnT aNd RuN sPeEd InCrEaSe 1桁の数字、5つの単語
  • -1 HiT (Reforged from CrItIcAl StRiKe ChAnCe) 負の1桁の数字、1ワード、3ワードのオプションの接尾辞

理想的なパターンは上記のボーナスエントリと一致する必要がありますが、一致する必要はありませ

ローカリゼーション

実際には、私が解析しようとしているすべての「数値」はローカライズされます。例:

  • +123,456英語(en-US)
  • +123.456ドイツ(de-DE)
  • +123'456フランス語(fr-CA)
  • +123 456エストニア語(et-EE)
  • +1,23,456アッサム語(as-IN)

いかなる回答も、これらのローカリゼーションの問題を説明しようとしてはなりません。番号が表示されるロケールがわからないため、番号のローカリゼーションが質問から削除されました。数字には、、、およびラテン数字から。までが含まれていると厳密に想定する必要があります。ローカライズされた数値を解析する方法はすでに知っています。この質問は、オプションのサフィックスを貪欲なパターンパーサーと一致させようとすることに関するものです。plus signhyphen minus09

編集:あなたは本当にローカライズされた番号を処理しようとする必要はありませんでした。あるレベルでは、ロケールを知らずにそれらを処理しようとするのは間違っています。たとえば、考えられる数字のローカリゼーションをすべて含めたわけではありません。もう1つは、将来どのようなローカリゼーションが存在するかわかりません。

4

4 に答える 4

8

うーん、私は 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
于 2012-11-29T06:39:25.147 に答える
1

複数のパターンを使用できるのに、なぜこれを1 つのパターンで解析するのでしょうか。

まず、番号を取得します。

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 パターンには制限があるため、実際のコードを使用して制限を回避することをお勧めします。

于 2012-11-29T06:05:06.450 に答える
0
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 ")))

単一のパターンではありませんが、機能します。

于 2012-11-29T06:10:11.473 に答える