ugrás a tartalomhoz

Javascript mintaillesztés, Node.js

deejayy · 2013. Feb. 13. (Sze), 14.54
Sziasztok,

egy elég misztikus hibába ütköztem, és nem nagyon tudok a végére járni.

Van egy node.js scriptem, UDP-n érkező adatokat dolgoz fel. A bejövő streamet természetsen stringgé alakítom és kivágom belőle azt, ami nekem kell.

Szóval van ez a kódrészlet:

res = this.patterns.logsync.exec(logLine);

console.log(logLine);
console.log(this.patterns.logsync);
console.log(res);
A konzolba az alábbiakat írja:

log L 02/13/2013 - 13:13:40: "rezso :D<13478><STEAM_0:0:123456789><CT>" logsync (ip "188.188.188.128:27005") (port "0") (hit "0") (hit_head "0") (hit_wall "3") (kill "21") (kill_head "8") (kill_wall "0") (shot "0") (death "7") (time "718")

/log L ([0-9]{2})/([0-9]{2})/([0-9]{4}) - ([0-9]{2}):([0-9]{2}):([0-9]{2}): "(.*?)<([0-9]+)><((STEAM|VALVE|BOT)(.*?))><([A-Z_]*)>" logsync .ip "(.*?)". .port "([0-9-]*)". .hit "([0-9-]*)". .hit_head "([0-9-]*)". .hit_wall "([0-9-]*)". .kill "([0-9-]*)". .kill_head "([0-9-]*)". .kill_wall "([0-9-]*)". .shot "([0-9-]*)". .death "([0-9-]*)". .time "([0-9-]*)"./gi

null

(sorkihagyások nincsenek, csak gondoltam tagolom a jobb olvashatóság miatt)

A "this.patterns.logsync" egy RegExp objektum.

A probléma az, hogy a harmadik console.log üzenet null-t ad vissza. Aminek persze nem nullnak kellene lennie.

A fenti adatokkal csináltam manuálisan egy js fájlt, és kipróbáltam, úgy mit ad.

#!/usr/bin/node

logLine = 'log L 02/13/2013 - 13:13:40: "rezso :D<13478><STEAM_0:0:123456789><CT>" logsync (ip "188.188.188.128:27005") (port "0") (hit "0") (hit_head "0") (hit_wall "3") (kill "21") (kill_head "8") (kill_wall "0") (shot "0") (death "7") (time "718")';
logsyncPattern = new RegExp('log L ([0-9]{2})/([0-9]{2})/([0-9]{4}) - ([0-9]{2}):([0-9]{2}):([0-9]{2}): "(.*?)<([0-9]+)><((STEAM|VALVE|BOT)(.*?))><([A-Z_]*)>" logsync .ip "(.*?)". .port "([0-9-]*)". .hit "([0-9-]*)". .hit_head "([0-9-]*)". .hit_wall "([0-9-]*)". .kill "([0-9-]*)". .kill_head "([0-9-]*)". .kill_wall "([0-9-]*)". .shot "([0-9-]*)". .death "([0-9-]*)". .time "([0-9-]*)".', 'gi');

res = logsyncPattern.exec(logLine);

console.log(logLine);
console.log(logsyncPattern);
console.log(res);
Az eredmény természetesen az elvárt, azaz a harmdik sorban nem null van, hanem egy tömb dumpja.

Kipróbáltam ugyanezt a http://www.regextester.com/-on is, beírva a megfelelő paramétereket, beállítva flageket (g és i), és úgy is helyes eredményt ad.

A dologhoz hozzá tartozik, hogy jön egyszerre mondjuk 7 sor adat, amiből 4 dolgozódik fel (4-re nem null a res változó értéke a regexp.exec után, hanem az elvárt). Az UDP fogadó nyilván async módon hívogatja meg az illesztést is tartalmazó függvényt, ahogy kap egy sort.
 
1

Biztos?

Poetro · 2013. Feb. 13. (Sze), 16.22
Biztosan előbb String-gé alakítottad a logLine-t? Nem lehet, hogy az még mindig StringBuffer, és azóta íródott bele adat?
2

Kódrészlettel válaszolnék,

deejayy · 2013. Feb. 14. (Cs), 10.56
Kódrészlettel válaszolnék, mert nem akarok hülyeséget mondani:

...
this.server.on('message', function (msg, rinfo) {
  ...
  var mystr = new String();
  mystr = msg.toString('utf8', 4, msg.length - 2);
  stat.parse(mystr);
  ...
});

...

this.parse = function (logLine) {
  ...
  res = this.patterns.logsync.exec(logLine);
  ...
}

...
Csináltam olyat is, hogy a regexp illesztés előtt is és utána is kiíratom a változók értékét, hátha közben változik, de nem, előtt is és utána is jók az értékek, csak az illesztés eredménye null...
3

Oké, fél siker: Ha már itt

deejayy · 2013. Feb. 14. (Cs), 11.27
Oké, fél siker:

Ha már itt tartunk, megnéztem úgy is a szcenáriót, hogy a regexp objektumot minden alkalommal létrehozom (new). Ekkor sikerült feldolgoznia minden beérkező kérést. Azt viszont nem értem, hogy egy számomra readonly objektum miért veszíti érvényét amikor több szálon használom fel.
4

A szálak függetlenek

Hidvégi Gábor · 2013. Feb. 14. (Cs), 16.33
A szálak függetlenek egymástól, ha jól értem a dolgot, az operációs rendszer külön folyamatként indít minden feldolgozást az esetedben, így a változók nem globálisak.
5

Van egy objektum (stat),

deejayy · 2013. Feb. 14. (Cs), 17.36
Van egy objektum (stat), amiben létrehozáskor beállítom a RegExp típusú változókat (ezek egy tömbben vannak felsorolva). A stat osztályból egy példány van.

Amit sejtesz, az szerintem nem magyarázza, hogy miért hagy ki egy-egy sort feldolgozásnál (ahogy írtam, 7-ből 4-nél nincs gond).

Ellenben ha a RegExp-eket akkor hozom létre, amikor a stat objektum metódusa megkapja az aktuális log sort, akkor minden rendben működik.
6

Cache

Poetro · 2013. Feb. 14. (Cs), 18.24
A JS motorok a regex-eket cachelik, és amennyiben még egyszer találkoznak a mintával, akkor a már feldolgozottat használják, azaz nem hozzák létre újra (kivéve a new RegExp esetén). Ez természetesen implementáció függő.
7

Most a regex-el van gond,

inf · 2013. Feb. 15. (P), 01.08
Most a regex-el van gond, vagy a string-el, amit feldolgozol? Érdemes lenne megnézni, hogy milyen regex dob vissza null-t, ha a szöveg rendben van.
8

Van egy olyan kellemetlen

MadBence · 2013. Feb. 15. (P), 13.19
Van egy olyan kellemetlen (nézőpont kérdése) tulajdonsága a RegExp objektumoknak, hogy van állapotuk. Az exec módosítja ezt az állapotot, majd a g flag miatt az exec ezt figyelembe is veszi (pontosan nem ismerem a mechanizmust, de gondolom a lastIndex tulajdonság miatt nem sikerül az illesztés)

Íme egy minimálpélda:

var reg=/alma/g;
var str=['almakörte','almakörte','almakörte'];
for(var i in str) { console.log(reg.exec(str[i])); }
Eredménye:
["alma", index: 0, input: "almakörte"]
null
["alma", index: 0, input: "almakörte"]
A megoldás:
Mindig létrehozni egy új RegExp objektumot, vagy az illesztés előtt a lastIndex tulajdonságot ki kell nullázni.
9

Ha ugyanazt a string-et adod

inf · 2013. Feb. 15. (P), 15.54
Ha ugyanazt a string-et adod neki, akkor nyilván a következő találatra fog ugrani, ezért kapsz a második alkalommal null-t. Az exec ugyanis lépked a találatok között egy string-en belül, így ciklussal ki lehet olvastatni vele az összes találatot...

String.match-et kell használni RegExp.exec helyett, vagy tisztában kell lenni azzal, hogy melyik függvény mit csinál...

var reg=/a(\d)/;
var regg=/a(\d)/g;
var str=['a1ba2','a1ba2','a1ba2'];

var exec = function (reg, stri){return reg.exec(stri);};
var match = function (reg, stri){return stri.match(reg);};

function display(title, reg, str, impl){
	console.log(title);  
	for(var i in str) {
		console.log(impl(reg, str[i]));
	}
}

display('exec global', regg, str, exec);
display('exec', reg, str, exec);
display('match global', regg, str, match);
display('match', reg, str, match);



exec global
["a1", "1"]
["a2", "2"]
null

exec
["a1", "1"]
["a1", "1"]
["a1", "1"]

match global
["a1", "a2"]
["a1", "a2"]
["a1", "a2"]

match
["a1", "1"]
["a1", "1"]
["a1", "1"]
10

Ha ugyanazt a string-et adod

MadBence · 2013. Feb. 15. (P), 17.04
Ha ugyanazt a string-et adod neki, akkor nyilván a következő találatra fog ugrani, ezért kapsz a második alkalommal null-t.

Nem kell ugyanannak a stringnek lennie:
var reg=/alma/g;  
var str=['almakörte','almabanán','almacitrom'];  
for(var i in str) { console.log(reg.exec(str[i])); }
["alma", index: 0, input: "almakörte"]
null
["alma", index: 0, input: "almacitrom"]
11

Hmm, hát akkor resetelni kell

inf · 2013. Feb. 15. (P), 21.24
Hmm, hát akkor resetelni kell minden új string feldolgozása előtt... Azt hittem, hogy van valami háttértároló, ahol lementi, hogy milyen string-hez milyen pozíció tartozik, de ezek szerint minden string-hez egyetlen változóba tolja az aktuális pozíciót. Lényeg a lényeg, hogy az exec global flag-gel arra való, hogy olyan string-ekből nyerjél ki adatot vele, ahol több találat is van az adott regex-re.