Regex für HTML color code
Danny K.
- javascript
Hi,
ich hab ein Textfeld, in das man einen HTML color code eintragen kann. Wenn da Unsinn drinsteht, erzeugt das einen Fehler, wenn man das als CSS Eigenschaft übernimmt. Also wollte ich das gerne vorher verifizieren, aber ich komm mit regex nicht auf einen grünen Zweig.
%[0-9a-f] funktioniert irgendwie nicht. Wer weiß, wie das geht?
%[0-9a-f] funktioniert irgendwie nicht. Wer weiß, wie das geht?
var eingabe = document.formular.hexa.value;
var muster = new RegExp('^[0-9a-f]{6}$', 'i');
alert(muster.test(eingabe) ? 'Funzt!' : 'Funzt net!');
Siechfred
hi,
ich hab ein Textfeld, in das man einen HTML color code eintragen kann.
Und damit meinst du sowas wie #abcabc - oder auch noch andere mögliche Schreibweisen?
Wenn da Unsinn drinsteht, erzeugt das einen Fehler, wenn man das als CSS Eigenschaft übernimmt. Also wollte ich das gerne vorher verifizieren, aber ich komm mit regex nicht auf einen grünen Zweig.
%[0-9a-f] funktioniert irgendwie nicht.
Ist ja auch "irgendwie" Unfug.
Wozu denn bitte ein Prozentzeichen?
Und du willst die erlaubten Zeichen genau 6 mal haben - oder 3 mal, wenn du auch die Kurzschreibweise akzeptieren willst. Also solltest du auch einen entsprechenden Quantifier nutzen.
Und darauf, dass sonst nichts drinsteht, wirst du auch noch achten wollen. Also ^ und $ für Zeichenkettenanfang und -ende nutzen.
gruß,
wahsaga
gudn tach!
ich hab ein Textfeld, in das man einen HTML color code eintragen kann. [...] wollte ich das gerne vorher verifizieren
willst du nur 6-stellige hex-werte zulassen?
/^#[0-9a-fA-F]{6}\z/
(erklaerung, "\z" heisst bloss "string-ende")
oder auch farbnahmen wie "black"? ausserdem sind eigentlich auch werte wie "#fff" zulaessig.
prost
seth
Hello out there!
%[0-9a-f] funktioniert irgendwie nicht.
'%' anstatt '#' ist jetzt nur ein Tippfehler?
[0-9a-f] bedeutet genau _ein_ Zeichen aus den angegeben. Du willst aber drei oder sechs. Außerdem müssen auch Großbuchstaben zugelassen weden.
#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})
Und was ist mit Farbangaben wie "red", "white", ...?
See ya up the road,
Gunnar
gruss Danny,
ich hab ein Textfeld, in das man einen HTML color code eintragen kann.
Wenn da Unsinn drinsteht, erzeugt das einen Fehler, wenn man das als
CSS Eigenschaft übernimmt. Also wollte ich das gerne vorher verifizieren, ...
genau ein regulaerer ausdruck fuer alle zulaessigen css-farb-schemata -
»rgb(255,255,255);«, »#ff00cc;« bzw. die ebenfalls moegliche kurzform
»#f0c;« sowie der farbname selber - ist machbar, aber sehr komplex und
im vorfeld seiner erstellung mit rechercheaufwand und schriftlicher
fleissarbeit verbunden - lesbar ist das teil dann aber nicht mehr:
var regXValidCssValues = (/^\s*(?:(?:aliceblue|antiquewhite|aqua|aquamarine|azure|beige|bisque|black|blanchedalmond|blue|blueviolet|brown|burlywood|cadetblue|chartreuse|chocolate|coral|cornflowerblue|cornsilk|crimson|cyan|darkblue|darkcyan|darkgoldenrod|darkgray|darkgreen|darkgrey|darkkhaki|darkmagenta|darkolivegreen|darkorange|darkorchid|darkred|darksalmon|darkseagreen|darkslateblue|darkslategray|darkslategrey|darkturquoise|darkviolet|deeppink|deepskyblue|dimgray|dimgrey|dodgerblue|firebrick|floralwhite|forestgreen|fuchsia|gainsboro|ghostwhite|gold|goldenrod|gray|green|greenyellow|grey|honeydew|hotpink|indianred|indigo|ivory|khaki|lavender|lavenderblush|lawngreen|lemonchiffon|lightblue|lightcoral|lightcyan|lightgoldenrodyellow|lightgray|lightgreen|lightgrey|lightpink|lightsalmon|lightseagreen|lightskyblue|lightslategray|lightslategrey|lightsteelblue|lightyellow|lime|limegreen|linen|magenta|maroon|mediumaquamarine|mediumblue|mediumorchid|mediumpurple|mediumseagreen|mediumslateblue|mediumspringgreen|mediumturquoise|mediumvioletred|midnightblue|mintcream|mistyrose|moccasin|navajowhite|navy|oldlace|olive|olivedrab|orange|orangered|orchid|palegoldenrod|palegreen|paleturquoise|palevioletred|papayawhip|peachpuff|peru|pink|plum|powderblue|purple|red|rosybrown|royalblue|saddlebrown|salmon|sandybrown|seagreen|seashell|sienna|silver|skyblue|slateblue|slategray|slategrey|snow|springgreen|steelblue|tan|teal|thistle|tomato|turquoise|violet|wheat|white|whitesmoke|yellow|yellowgreen|activeborder|activecaption|appworkspace|background|buttonface|buttonhighlight|buttonshadow|buttontext|captiontext|graytext|highlight|highlighttext|inactiveborder|inactivecaption|inactivecaptiontext|infobackground|infotext|menu|menutext|scrollbar|threeddarkshadow|threedface|threedhighlight|threedlightshadow|threedshadow|window|windowframe|windowtext)|(?:#(?:[a-f]|[0-9]){3}(?:(?:[a-f]|[0-9]){3})?)|(?:rgb\(\s*([0-9]{1,3}\s*,\s*[0-9]{1,3}\s*,\s*[0-9]{1,3})\s*\)))\s*$/i);
geklaut hab ich den aus einem meiner alten testcases - dieser hat jetzt
auch schon zwei jahre auf dem buckel:
http://www.pseliger.de/jsExtendedApi/jsApi.DHTMLCssColor.dev.js
ACHTUNG, die dazugehoerige testumgebung produziert 34 alerts:
http://www.pseliger.de/jsExtendedApi/jsApi.DHTMLCssColor.dev.html
viel spass - peterS. - pseliger@gmx.net
hallo again Danny,
ich hab' den ausdruck jetzt lieber nochmal selbst getestet ... also:
das ding schlaegt sich sehr tapfer bei farbnamen und sowohl bei
der kurzen als auch der langen hexadezimalschreibweise, auch
beim rgb-muster versagt das ding nicht, solange die schreibweise
schematisch stimmt. natuerlich muss der ausdruck bei ungueltigen
dezimalen werten (hier werte ueber 255 - zb.: rgb(0,0,999))
versagen - RegExp testen eben nun mal nur muster.
dir wird also nichts anderes uebrigbleiben, als dem schematischen
test auch noch einen auf plausibilitaet folgen zu lassen. diesen test
kannst Du Dir selber stricken, oder Du benutzt das zuvor verlinkte
JavaScript-modul.
so long - peterS. - pseliger@gmx.net
gudn tach!
das ding schlaegt sich sehr tapfer bei farbnamen und sowohl bei
der kurzen als auch der langen hexadezimalschreibweise, auch
beim rgb-muster versagt das ding nicht, solange die schreibweise
schematisch stimmt. natuerlich muss der ausdruck bei ungueltigen
dezimalen werten (hier werte ueber 255 - zb.: rgb(0,0,999))
versagen - RegExp testen eben nun mal nur muster.dir wird also nichts anderes uebrigbleiben[...]
doch!
statt
/[0-9]{1,3}/
"einfach"
/2(?:5[0-5]|[0-4]\d)|(?:1\d|[1-9])?\d/
verwenden. ;-)
es gibt sogar leute, die basteln kalender damit.
prost
seth
gruss seth
doch!
Du hast recht; da kann man schon was machen.
statt
/[0-9]{1,3}/
"einfach"
/2(?:5[0-5]|[0-4]\d)|(?:1\d|[1-9])?\d/
verwenden. ;-)
wenn ich den ausdruck so lese, glaub ich aber nicht, dass
dieser ueberhaupt fuer den gedachten zweck taugt - hast Du
das ding ausprobiert? angewandt auf den test weiter unten
bekomme ich immer [true].
ich hab' mich mal an nur einer zahl zwischen 0 und 255
versucht:
~~~javascript
// folgende alternativen jeweils zwischen
// anfang und ende einer zeichenketten:
[1]$| // entweder einstellig : 0-9
(?:[2][0-9])$| // oder zweistellig : 10-99
(?:^1[0-9][0-9])$| // oder dreistellig : 100-199
(?:^2[0-5][0-5])$ // oder dreistellig : 200-255
var regXRGBValue = (/[3]$|(?:[4][0-9])$|(?:^1[0-9][0-9])$|(?:^2[0-5][0-5])$/);
alert(regXRGBValue.test("-1")); // false;
alert(regXRGBValue.test("0")); // true;
alert(regXRGBValue.test("1")); // true;
alert(regXRGBValue.test("10")); // true;
alert(regXRGBValue.test("99")); // true;
alert(regXRGBValue.test("199")); // true;
alert(regXRGBValue.test("299")); // false;
alert(regXRGBValue.test("256")); // false;
alert(regXRGBValue.test("260")); // false;
alert(regXRGBValue.test("255")); // true;
bestimmt kann man das noch optimieren ... ich bin alles
andere als ein RegExp-experte. als basis fuer ein auf
validitaet pruefendes css-rgb-schema fuer werte wie z.b.
»rgb (0, 128, 256)« wuerde ich das trotzdem nicht nehmen
wollen - die arme RegExp-engine.
> es gibt sogar leute, die [basteln kalender](http://forum.de.selfhtml.org/archiv/2006/3/t126272/#m814810) damit.
ja, ja, der Gunnar ... das ist doch krank oder ?-)
so long - peterS. - pseliger@gmx.net
--
»Because objects in JavaScript are so flexible, you will want to think differently about class hierarchies.
Deep hierarchies are inappropriate. Shallow hierarchies are efficient and expressive.« - [Douglas Crockford](http://javascript.crockford.com/)
ie:( fl:) br:> va:( ls:& fo:) rl:| n3;} n4:} ss:} de:µ js:} mo:? zu:]
gudn tach!
statt
/[0-9]{1,3}/
"einfach"
/2(?:5[0-5]|[0-4]\d)|(?:1\d|[1-9])?\d/
verwenden. ;-)wenn ich den ausdruck so lese, glaub ich aber nicht, dass
dieser ueberhaupt fuer den gedachten zweck taugt - hast Du
das ding ausprobiert?
hatte ich noch nicht.
aber kann ich ja mal machen...
hmm, bei mir klappt das:
$ perl -e 'for (-1,0,1,10,99,199,299,256,260,255){print "$_\n" if /^(?:2(?:5[0-5]|[0-4]\d)|(?:1\d|[1-9])?\d)\z/;}'
0
1
10
99
199
255
wuesste nicht, was daran falsch sein soll.
prost
seth
hallo seth,
statt
/[0-9]{1,3}/
"einfach"
/2(?:5[0-5]|[0-4]\d)|(?:1\d|[1-9])?\d/
verwenden. ;-)
»»
... - hast Du das ding ausprobiert? angewandt auf den test
weiter unten bekomme ich immer [true].
aber kann ich ja mal machen...
hmm, bei mir klappt das:
$ perl -e 'for (-1,0,1,10,99,199,299,256,260,255){print "$_\n" if /^(?:2(?:5[0-5]|[0-4]\d)|(?:1\d|[1-9])?\d)\z/;}'
0
1
10
99
199
255wuesste nicht, was daran falsch sein soll.
nichts - ich hab' das einfach so bei Dir abgeschrieben (siehe ganz oben) und
dem ding dann genau die begrenzer verwehrt - ^$ - die ich meinem bsp. dann
umso grosszuegiger spendiert habe.
$ perl -e 'for (-1,0,1,10,99,199,299,256,260,255){print "$_\n" if /^(?:2(?:5[0-5]|[0-4]\d)|(?:1\d|[1-9])?\d)\z/;}'
geile syntax - so aehnlich koennen wir browserfuzzies das jetz auch:
sowohl ...
alert( // meinereiniger
[-1,0,1,10,99,199,299,256,260,255].filter(function (elm/*, idx, arr*/) {
return ((/^[0-9]$|(?:^[1-9][0-9])$|(?:^1[0-9][0-9])$|(?:^2[0-5][0-5])$/).test(elm));
})
);
bzw. (achtung nur fuer die konsole oder die adressezeile von mozillas geeignet)
alert([-1,0,1,10,99,199,299,256,260,255].filter(function(elm){return((/^[0-9]$|(?:^[1-9][0-9])$|(?:^1[0-9][0-9])$|(?:^2[0-5][0-5])$/).test(elm));}));
... als auch ..
alert( // deinereiniger JavaScript-kompatibel gemacht:
[-1,0,1,10,99,199,299,256,260,255].filter(function (elm/*, idx, arr*/) {
return ((/^(?:2(?:5[0-5]|[0-4]\d)|(?:1\d|[1-9])?\d)$/).test(elm));
})
);
bzw.
alert([-1,0,1,10,99,199,299,256,260,255].filter(function(elm){return((/^(?:2(?:5[0-5]|[0-4]\d)|(?:1\d|[1-9])?\d)$/).test(elm));}));
... melden gleichlautend »0,1,10,99,199,255« - sehr schoen - wieder was gelernt.
dankbar gruessend - peterS. - pseliger@gmx.net
gudn tach!
$ perl -e 'for (-1,0,1,10,99,199,299,256,260,255){print "$_\n" if /^(?:2(?:5[0-5]|[0-4]\d)|(?:1\d|[1-9])?\d)\z/;}'
geile syntax
ja, perl rockt!
- so aehnlich koennen wir browserfuzzies das jetz auch:
alert([-1,0,1,10,99,199,299,256,260,255].filter(function(elm){return((regexp).test(elm));}));
oh, diese filter-methode kannte ich noch nicht. zwar macht javascript perl damit imho keine ernstzunehmende konkurrerenz in puncto syntax *g*, aber sehr nett und nuetzlich ist dieses filter schon mal auf jeden fall.
prost
seth
gudn tach!
ich musste eben ganz dringend weg, was essen und bier trinken, weswegen ich jetzt noch mal antworte; halt auf den rest.
~~~javascript
[1]$| // entweder einstellig : 0-9
(?:[2][0-9])$| // oder zweistellig : 10-99
(?:^1[0-9][0-9])$| // oder dreistellig : 100-199
(?:^2[0-5][0-5])$ // oder dreistellig : 200-255var regXRGBValue = (/[3]$|(?:[4][0-9])$|(?:^1[0-9][0-9])$|(?:^2[0-5][0-5])$/);
alert(regXRGBValue.test("-1")); // false;
alert(regXRGBValue.test("0")); // true;
alert(regXRGBValue.test("1")); // true;
alert(regXRGBValue.test("10")); // true;
alert(regXRGBValue.test("99")); // true;
alert(regXRGBValue.test("199")); // true;
alert(regXRGBValue.test("299")); // false;
alert(regXRGBValue.test("256")); // false;
alert(regXRGBValue.test("260")); // false;
alert(regXRGBValue.test("255")); // true;
und damit hast du wunderbar demonstriert, welchen nachteil blackbox-tests haben. denn...
> (?:^2[0-5][0-5])$ // oder dreistellig : 200-255
noe, weil
> alert(regXRGBValue.test("206")); // false;
moep! ;-)
die gruppierungen (also die klammern) sind bei dir uebrigens ueberfluessig.
also:
/^[0-9]$|^[1-9][0-9]$|^1[0-9][0-9]$|^2[0-4][0-9]$|^25[0-5]$/
(und beachte, dass $ auch "\n" zulaesst)
prost
seth
guten morgen,
und damit hast du wunderbar demonstriert, welchen nachteil blackbox-tests »» haben. denn...
...
noe, weilalert(regXRGBValue.test("206")); // false;
moep! ;-)
au backe - schaem ... naja, wenigstens habe ich in der zwischenzeit
Dein suchmuster verstanden.
die gruppierungen (also die klammern) sind bei dir uebrigens ueberfluessig.
also:
/[1]$|[2][0-9]$|^1[0-9][0-9]$|^2[0-4][0-9]$|^25[0-5]$/
ich mag aber klammern.
(und beachte, dass $ auch "\n" zulaesst)
jawoll.
so long - peterS. - pseliger@gmx.net
Hi,
var regXRGBValue = (/[1]$|(?:[2][0-9])$|(?:^1[0-9][0-9])$|(?:^2[0-5][0-5])$/);
Unvollständig.
alert(regXRGBValue.test("206")); // false, müßte aber true sein
alert(regXRGBValue.test("217")); // false, müßte aber true sein
alert(regXRGBValue.test("228")); // false, müßte aber true sein
alert(regXRGBValue.test("239")); // false, müßte aber true sein
alert(regXRGBValue.test("246")); // false, müßte aber true sein
^2[0-5][0-5]
Bei dreistelligen Zahlen mit 2 am Anfang läßt Du als letzte Ziffer nur 0 bis 5 zu, 6 bis 9 sind aber zulässig, falls die 2. Ziffer 0 bis 4 ist.
cu,
Andreas
gudn tach!
Bei dreistelligen Zahlen mit 2 am Anfang läßt Du als letzte Ziffer nur 0 bis 5 zu, 6 bis 9 sind aber zulässig, falls die 2. Ziffer 0 bis 4 ist.
baetsch, ich war 7 stunden schneller. ;-)
prost
seth
Hi,
Bei dreistelligen Zahlen mit 2 am Anfang läßt Du als letzte Ziffer nur 0 bis 5 zu, 6 bis 9 sind aber zulässig, falls die 2. Ziffer 0 bis 4 ist.
baetsch, ich war 7 stunden schneller. ;-)
Ich hatte das Posting heute kurz nach Mitternacht abgeschickt und hab dann in einem anderen Tab weitergelesen und nicht mehr drauf geachtet. Warum das Posting erst heute morgen ankam, weiß ich nicht.
cu,
Andreas
gruss Andreas, hallo seth,
var regXRGBValue = (/[1]$|(?:[2][0-9])$|(?:^1[0-9][0-9])$|(?:^2[0-5][0-5])$/);
Unvollständig.
...
^2[0-5][0-5]
Bei dreistelligen Zahlen mit 2 am Anfang läßt Du als letzte Ziffer nur
0 bis 5 zu, 6 bis 9 sind aber zulässig, falls die 2. Ziffer 0 bis 4 ist.
jo, seth hat mich fuer diesen zweck ja einen besseren ausdruck gelehrt.
mein altes schema konsequent durchgezogen sollte jetzt aber funktionieren:
var regXRGBValue = (/
^[0-9]$| // 0 - 9
^[1-9][0-9]$| // 10 - 99
^1[0-9][0-9]$| // 100 - 199
^2[0-4][0-9]$| // 200 - 249
^25[0-5]$ // 250 - 255
/);
alert(
[-1,0,9,10,99,100,199,200,299,249,250,255,256].filter(function (elm/*, idx, arr*/) {
return ((/^[0-9]$|^[1-9][0-9]$|^1[0-9][0-9]$|^2[0-4][0-9]$|^25[0-5]$/).test(elm));
})
);
bzw. konsolentestfaehig:
alert([-1,0,9,10,99,100,199,200,299,249,250,255,256].filter(function(elm){return((/^[0-9]$|^[1-9][0-9]$|^1[0-9][0-9]$|^2[0-4][0-9]$|^25[0-5]$/).test(elm));}));
liefert mir brav »0,9,10,99,100,199,200,249,250,255« zurueck.
klaert mich bitte mal auf - welcher ausdruck wuerde denn nach der theorie von
einer regex-engine performanter verarbeitet werden - der von mir ueberarbeitete,
oder seths dahingeperlter - (/^(?:2(?:5[0-5]|[0-4]\d)|(?:1\d|[1-9])?\d)$/)
- und
vor allem, warum?
dankend - peterS. - pseliger@gmx.net
Hi,
gruss Andreas, hallo seth,
var regXRGBValue = (/[1]$|(?:[2][0-9])$|(?:^1[0-9][0-9])$|(?:^2[0-5][0-5])$/);
Unvollständig.
...
^2[0-5][0-5]
Bei dreistelligen Zahlen mit 2 am Anfang läßt Du als letzte Ziffer nur
0 bis 5 zu, 6 bis 9 sind aber zulässig, falls die 2. Ziffer 0 bis 4 ist.jo, seth hat mich fuer diesen zweck ja einen besseren ausdruck gelehrt.
mein altes schema konsequent durchgezogen sollte jetzt aber funktionieren:
var regXRGBValue = (/
[3]$| // 0 - 9
[4][0-9]$| // 10 - 99
^1[0-9][0-9]$| // 100 - 199
^2[0-4][0-9]$| // 200 - 249
^25[0-5]$ // 250 - 255/);
alert(
[-1,0,9,10,99,100,199,200,299,249,250,255,256].filter(function (elm/, idx, arr/) {
return ((/[5]$|[6][0-9]$|^1[0-9][0-9]$|^2[0-4][0-9]$|^25[0-5]$/).test(elm));
})
);
>
> bzw. konsolentestfaehig:
>
> ^[0-9]$|^[1-9][0-9]$|^1[0-9][0-9]$|^2[0-4][0-9]$|^25[0-5]$
Was hierbei schlecht ist:
Es wird auf jeden Fall mal in den ersten Fall reingerannt, auch wenn's mehr als zwei Ziffern sind.
Bei Alternativen nach Möglichkeit immer die spezifischsten Anfänge nach vorne, damit möglichst schnell entschieden ist, welcher Zweig zutreffen kann, also hier der Fall mit 25, dann die Fälle mit 1 bzw. 2, dann der zweistellige.
Außerdem: ALLE Deine Alternativen enthalten die Anker ^ und $.
Die ersten zwei Deiner Möglichkeiten lassen sich noch mit einem ? nach der [1-9] zusammenfassen.
Also besser: ^ und $ außerhalb der Alternative:
^(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])$
Je nach Regex-Engine könnte \d anstelle von [0-9] noch was ausmachen.
Oder die Zusammenfassung der ersten zwei Fälle 25[0-5]|2[0-4][0-9] zu 2(?:5[0-5]|[0-4][0-9]), weil dann das backtracking nur bis zur 2 zurückgeht, nicht bis zum Stringanfang, wenn der zweite Fall eintrifft (wobei hier dann noch die Reihenfolge umgedreht werden könnte zu 2(?:[0-4][0-9]|5[0-5]) - die erste Alternative deckt jetzt 50 Fälle (200 - 249) ab, die zweite nur 6 (250 - 255) - ob das was ausmacht, hängt natürlich auch von der Verteilung der zu matchenden Daten ab)
cu,
Andreas
--
[Warum nennt sich Andreas hier MudGuard?](http://MudGuard.de/)
[O o ostern ...](http://ostereier.andreas-waechter.de/)
Fachfragen unaufgefordert per E-Mail halte ich für unverschämt und werde entsprechende E-Mails nicht beantworten. Für Fachfragen ist das Forum da.
gudn tach!
Bei Alternativen nach Möglichkeit immer die spezifischsten Anfänge nach vorne, damit möglichst schnell entschieden ist, welcher Zweig zutreffen kann,
wenn nichts ueber den string bekannt ist, dann ack.
aber wenn man gewissen vorwissen hat, sollten u.u.(!) wahrscheinlichere zweige nach vorne.
Die ersten zwei Deiner Möglichkeiten lassen sich noch mit einem ? nach der [1-9] zusammenfassen.
das wiederum fuehrt zu backtracking (im regexp), was man, wenn man viel wert auf speed legt, vermeiden sollte.
Je nach Regex-Engine könnte \d anstelle von [0-9] noch was ausmachen.
oh, das wusste ich noch nicht. kannst du dazu mehr sagen (z.b. welche engines das betrifft)?
zum rest kann ich nur noch "ack" sagen.
prost
seth
Hi,
Je nach Regex-Engine könnte \d anstelle von [0-9] noch was ausmachen.
oh, das wusste ich noch nicht. kannst du dazu mehr sagen (z.b. welche engines das betrifft)?
Steht irgendwo bei J. Friedl, Mastering Regular Expressions - ich müßt das jetzt auch erst raussuchen.
Nicht betroffen sind jedenfalls all die Regex-Engines, die \d gar nicht kennen ;-)
cu,
Andreas
hallo Ihr beiden,
@MudGuard - dank auch Dir an dieser stelle fuer die aufklaerungsarbeit.
Steht irgendwo bei J. Friedl, Mastering Regular Expressions ...
ja, bei dem hab' ich auch mal nachgeschlagen, um ihm seine tests auf
regex-implementationen zu klauen. denn ich wollte wissen, was die
browser so unter ihrer [[RegExp]]-haube verstecken, natuerlich noch
ohne einen schimmer davon habend, was ich selbst mit den gewonnenen
informationen jemals anfangen koennte.
getested wurden mozilla rv 1.7.12, firefox 1.5.0.7 , opera 8.5.77,
opera 9, msie 6.0 - alle liefern die gleichen ergebnisse, so dass
davon auszugehen ist, dass ein fuer alle verbindliches papier zur
implementation von RegExp-maschinen-typen existiert.
http://www.pseliger.de/jsExtendedApi/jsApi.RegExp.testForEngineTypes.dev.js
die test ergeben folgendes bild:
- die [RegExp]-objekte aller getesteten browser lassen standardmaessig
eine NFA-engine auf die regulaeren ausdruecke los.
- kommt die mit dem suchmuster nicht zurecht wird eine POSIX-NFA-engine
angeworfen. dabei treten betraechtliche zeitverzoegerungen auf. in
meinem test zwischen 4 (msie) und 10 (gecko) sekunden.
- der dritte typ, DFA-engine, ist bei keinem der browser implementiert.
falls Ihr noch den drang verspuert, mir in kurzen einpraegsamen worten
zu erklaeren was denn nun der genaue unterschied in der arbeitsweise
zumindets der ersten beiden genannten NFA/POSIX-NFA zu erklaeren, bin
ich Euch kein bischen boese ;-)
so long - peterS. - pseliger@gmx.net
Hi,
falls Ihr noch den drang verspuert, mir in kurzen einpraegsamen worten
zu erklaeren was denn nun der genaue unterschied in der arbeitsweise
zumindets der ersten beiden genannten NFA/POSIX-NFA zu erklaeren, bin
ich Euch kein bischen boese ;-)
Jeffrey macht das IIRC recht gut.
Wenn's Dich wirklich interessiert, lies das Buch.
cu,
Andreas
gudn tach!
[erklaeren, was] der genaue unterschied in der arbeitsweise
zumindets der ersten beiden genannten NFA/POSIX-NFA [ist]Jeffrey macht das IIRC recht gut.
Wenn's Dich wirklich interessiert, lies das Buch.
auszuege daraus gibt's sogar online.
prost
seth
gudn tach!
klaert mich bitte mal auf - welcher ausdruck wuerde denn nach der theorie von
einer regex-engine performanter verarbeitet werden - der von mir ueberarbeitete,
oder seths dahingeperlter -(/^(?:2(?:5[0-5]|[0-4]\d)|(?:1\d|[1-9])?\d)$/)
- und
vor allem, warum?
puh, also das kommt sehr darauf an, wie die strings aussehen, auf welche die ausdruecke losgelassen werden.
ein regexp-parser arbeitet den ausdruck von links nach rechts ab, und schaut jeweils, ob's passt. der string wird ebenfalls von links nach rechts abgearbeitet; wobei wird dort u.u. wieder an den anfang des strings gesprungen. ebenso kann beim regexp durch backtracking (siehe z.b. wikipedia) gesprungen werden.
am bsp. wird's klarer:
string = "7":
regexp = /^[0-9]$|^[1-9][0-9]$|^1[0-9][0-9]$|^2[0-4][0-9]$|^25[0-5]$/
^ matcht den anfang
[0-9] matcht 7
$ matcht das ende
fertig
das gleiche in umgekehrter reihenfolge, also
regexp = /^25[0-5]$|^2[0-4][0-9]$|^1[0-9][0-9]$|^[1-9][0-9]$|^[0-9]$/
^ matcht den anfang
2 matcht nicht
5[0-5]$ erst recht nicht
| vergesse bisher gematchtes
^ matcht den anfang
2 usw.
usw. bis halt irgendwann...
^ matcht den anfang
[0-9] matcht die 7
$ matcht das ende
endlich fertig
und jetzt meins:
regexp = /^(?:2(?:5[0-5]|[0-4]\d)|(?:1\d|[1-9])?\d)$/
^ matcht den anfang
2 matcht nicht
| vergiss die "2", veraendere den pointer im string aber nicht
1 matcht nicht
|
[0-9] matcht 7
? wird vorerst ignoriert, aber falls spaeter etwas nicht gematcht wird, wird gebacktracked
\d matcht nicht!
backtracking (gematchte '7' wird vergessen)
\d matcht '7'
$ matcht das ende
endlich fertig
so in etwa.
das backtracking frisst sehr viel zeit. sieht man auch beim benchmarking:
#!/usr/bin/perl
use strict;
use Benchmark qw(:all) ;
my $s = '7';
my $results = timethese(5_000_000, {
'schnell' => sub{$s=~/^[0-9]$|^[1-9][0-9]$|^1[0-9][0-9]$|^2[0-4][0-9]$|^25[0-5]$/;},
'lahm' => sub{$s=~/^25[0-5]$|^2[0-4][0-9]$|^1[0-9][0-9]$|^[1-9][0-9]$|^[0-9]$/;},
'seth' => sub{$s=~/^(?:2(?:5[0-5]|[0-4]\d)|(?:1\d|[1-9])?\d)$/;},
'seth2' => sub{$s=~/^(?:2(?:5[0-5]|[0-4]\d)|(?:1\d|[1-9])\d|\d)$/;},
},'none'
);
cmpthese($results);
fuehrt bei mir zu
("7")
Rate seth lahm seth2 schnell
seth 1016260/s -- -34% -42% -59%
lahm 1533742/s 51% -- -12% -38%
seth2 1742160/s 71% 14% -- -30%
schnell 2487562/s 145% 62% 43% --
ist natuerlich relativ ungenau, aber nicht zu sehr.
hier spiegelt sich in etwa das wieder, was ich oben beschrieben habe.
"seth2" ist derselbe ausdruck wie "seth" mit dem unterschied, dass das backtracking ansichtlich umgangen wird.
bei einem laengeren string dagegen, also z.b. "250", waere "schnell" lahm und "lahm" schnell:
("250")
Rate schnell seth lahm seth2
schnell 1445087/s -- -20% -27% -33%
seth 1798561/s 24% -- -9% -16%
lahm 1968504/s 36% 9% -- -8%
seth2 2145923/s 48% 19% 9% --
da hier backtracking gar nicht noetig waere, waere "schnell" sogar der lahmste, wobei die unterschiede hier nicht ganz so gross waeren.
sorry, dass ich's nur so grob erklaert habe, auf papier waer's einfacher und wuerde nicht so viel arbeit machen. ;-)
prost
seth
gruss seth,
vielen dank fuer Deine geduld, muehe und umfangreichen
erklaerungen - Dein posting liegt jetzt auf dem ersten
platz meiner doch sehr ueberschaubaren bookmarkliste
zu regulaeren ausdruecken.
*wieder etwas klueger* - peterS. - pseliger@gmx.net