Wie auch in der Lua-Doku beschrieben, kann bei string.gmatch kein Caret als Anker verwendet werden, da dies die Iteration verhindern würde.
(Habe ich anfangs überlesen und wie blöd nach dem Fehler gesucht. Solche extrem wichtigen Infos hätte ich in fetter Rotschrift erwartet. )
Hier mal ein fiktives Beispiel. Es sollen aus einem String alle alleinstehenden Ziffern(-gruppen) (getrennt durch Leerzeichen) gefunden werden.
Da die reinen Stringpattern kein Oder ermöglichen, sind mehrere Pattern nacheinander anzuwenden um alle Möglichkeiten zu berücksichtigen.
- Zifferngruppe gefolgt von Leerzeichen
- Zifferngruppe nach Leerzeichen am Stringende
- String enthält nur die Zifferngruppe
Um die letzte Bedingung zu erfüllen und keine Matches auf bereits durch die vorigen Pattern gefundenen Gruppen zu haben muss ich als Anker Stringanfang und -ende mit angeben. Aber, wie oben angeführt, ist das mit string.gmatch nicht möglich.
Ich zeige das mal hier im Bsp.
Beispiel
local tStr = {
"007 0xFF 123 777cd 456 0x0011AB 789", --> 007 123 456 789
" 007", --> 007
"007"} --> 007
local tPatt = {
"(%d+)%s", --> alle Zifferngruppen, denen ein Leerzeichen folgt
"%s(%d+)$", --> Zifferngruppe nach Leerzeichen am Stringende
"^(%d+)$"} --> String besteht nur aus Zifferngruppe
local tExpect = {
{"007 123 456","789",""},
{"","007",""},
{"","","007"}}
for i=1, #tStr do
print('>> STRING "'..tStr[i]..'"')
for j=1, #tPatt do
local m = ''
print('->\tPATTERN "'..tPatt[j]..'", erwartet: "'..tExpect[i][j]..'"')
for match in tStr[i]:gmatch(tPatt[j]) do
m = m..match..' '
end
m = m:gsub('%s+$','')
local pm = '+'
if tExpect[i][j] ~= m then pm = '!' end
print(pm..'>\tMATCH "'..m..'"')
end
end
Alles anzeigen
Ergebnis
>> STRING "007 0xFF 123 777cd 456 0x0011AB 789"
-> PATTERN "(%d+)%s", erwartet: "007 123 456"
+> MATCH "007 123 456"
-> PATTERN "%s(%d+)$", erwartet: "789"
+> MATCH "789"
-> PATTERN "^(%d+)$", erwartet: ""
+> MATCH ""
>> STRING " 007"
-> PATTERN "(%d+)%s", erwartet: ""
+> MATCH ""
-> PATTERN "%s(%d+)$", erwartet: "007"
+> MATCH "007"
-> PATTERN "^(%d+)$", erwartet: ""
+> MATCH ""
>> STRING "007"
-> PATTERN "(%d+)%s", erwartet: ""
+> MATCH ""
-> PATTERN "%s(%d+)$", erwartet: ""
+> MATCH ""
-> PATTERN "^(%d+)$", erwartet: "007"
!> MATCH ""
Wie kann man das umgehen? - Durch Verwendung einer String-Funktion, die Anker im Pattern nutzen kann, string.match.
Als Lösung prüfe ich vor Ausführung von gmatch, ob nur die letzte (durch gmatch nicht erkennbare) Bedingung erfüllt ist mit match.
Somit wird gmatch nur auf Strings angewendet, die mit den möglichen Pattern auch verarbeitbar sind.
local tRes = {}
table.insert(tRes, strTest:match('^(%d+)$')) -- fügt Treffer ein oder nil
if #tRes == 0 then
-- weiter mit :gmatch
end
Das ist etwas Code mehr, aber erfüllt den Zweck.