PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [JS] RegExp mit Variablen



TruckerB
20.03.2014, 12:46
Hallo zusammen,
ich habe mich lange nicht mehr hier blicken lassen, aber jetzt sitze ich vor einem Codeschnipsel, bei dem ich einfach nicht weiter komme und habe mich an die gute hilfe hier im Forum erinnert ;)

Also: Ich habe eine Variable (tags) die tags enthält. Wenn der User nun neue Tags hinzu fügt soll erst überprüft werden ob der Tag bereits in dieser Variable ist. (Wird dann später weiter verarbeitet)

function add_tags(str) {
var Suche = new RegExp("\b" + str + "\b");
var Ergebnis = Suche.test(tags);
if(Ergebnis) {
alert("Gefunden!");
} else {
alert("Nicht Gefunden... Tags: _"+tags+"_\nString: _"+str+"_")
}
}
In str wird der Tag, der hinzugefügt werden soll, an die Funktion übergeben. Der Fehler liegt irgendwo im Suchmuster...
In der Variable tags habe ich das Wort "Tag1". Und in str übergebe ich "Tag1".
Die Suche soll aber nur bei absolut dem gleichen Wort erfolgreich sein. Nicht bei "Tag" oder so, deswegen die \b. Ohne diese Syntax(?) (\b) Funktioniert es, aber die Suche ist auch bei Tag2 etc. erfolgreich...

Übrigens, wenn ich die Variable weg lasse und "\bTag1\b" schreibe klappt es auch... die Kombination macht es :/

jabu
22.03.2014, 16:09
Vorweg: Ich kenne mich nicht gut mit JavaScript aus. Aber eines ist mir wegen der Ähnlichkeit zu C oder C++ aufgefallen:

JavaScript verwendet ebenfalls Escape-Sequenzen (https://de.wikipedia.org/wiki/Escape-Sequenz) in Zeichenketten. Also ist \b innerhalb eines String-Literals das Backspace (https://de.wikipedia.org/wiki/Backspace)-Zeichen und nicht die Zeichenfolge aus \ und b.

Wenn man also das Backslash-Zeichen selbst haben möchte, muss man dieses durch seine Escape-Sequenz ersetzen. Zum Glück ist das einleuchtend umgesetzt, sodass man nichts extra auswendiglernen muss: "\\". Also müsste es jeweils "\\b" heißen, damit im String selbst \b steht.

Du verwendst ja selbst "\n", um einen Zeilenvorschub herbeizuführen, weshalb ich mir nicht sicher bin, ob du es einfach nur übersehen hast, oder ob Folgendes nicht ganz geklärt ist:

Es spielt nämlich keine Rolle, was später die Methode mit der Zeichenkette anstellt, ob sie Regular Expressions darüberlaufen lässt oder eine E-Mail daraus strickt. Denn Escape-Sequenzen werden gleich in einer frühen Stufe, nämlich im Lexer (https://de.wikipedia.org/wiki/Lexikalischer_Scanner) vor dem eigentlichen Parser (https://de.wikipedia.org/wiki/Parser) in die entsprechenden Codes (z.B. ASCII) umgesetzt, weshalb nicht mehr als eine Zahl übrig bleibt, z.B. ein Byte oder ein Vielfaches davon (je nach Zeichensatz und innerer Repräsentation), so wie bei anderen Zeichen auch.

jabu
22.03.2014, 22:51
Hab's ganz grob ausprobiert, geht:

<html>
<head><title>Test</title>
<script type="text/javascript">
<!--
var tags = "lhz Tag1 käki öl";

function add_tags(str) {

var pattern = new RegExp("\\b" + str + "\\b");
var isfound = pattern.test(tags);

if(isfound) {
alert("Gefunden!");
} else {
alert("Nicht Gefunden... Tags: "+tags+"\nString: "+str);
}
}
//-->
</script>
</head>
<body>
<form name="" action="">
<input type="text" name="Eingabe" size="8">
<input type="button" value="Pr&uuml;fe Zeichenkette" onclick="add_tags(this.form.Eingabe.value)">
</body>
</html>

Fertiger Code sieht natürlich anders aus. Gibt man z.B. ein Leerzeichen am Anfang des Suchwortes ein, so ist die Bedingung ebenso erfüllt, bei mehreren Leerzeichen natürlich nicht. Gibt man RegExps mit ein, werden sie zum Teil des Gesamtausdrucks, weil jegliche Filterung fehlt. Überhaupt wäre zu bedenken, ob man das so braucht.

jabu
23.03.2014, 01:32
Ab hier wird's langsam einigermaßen brauchbar:

<html>
<head><title>Test</title>
<script type="text/javascript">
<!--
var tags = "df Tag1 +k\".ä.*\\[2 öl";

function add_tags(str) {

str = str.trim();

var escaped = str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
var pattern = new RegExp("\\b" + escaped + "\\b");
var isfound = pattern.test(tags);

if(isfound) {
alert("Gefunden!");
} else {
alert("Nicht Gefunden... Tags: "+tags+"\nString: "+str);
}
}
//-->
</script>
</head>
<body>
<form name="" action="">
<input type="text" name="Eingabe" size="8">
<input type="button" value="Pr&uuml;fe Zeichenkette" onclick="add_tags(this.form.Eingabe.value)">
</body>
</html>
Mit str.trim() werden zu Komfortzwecken die führenden und endenden Whitespaces von der Eingabe beseitigt. Das Escapen wirkt sich nur auf die Suche aus, nicht auf den Inhalt, sodass im String tags beliebiges Zeugs berücksichtigt werden kann.

So ist z.B. nicht nur eine Suche nach " Tag1 " erfolgreich, sondern auch eine nach " Tag1 +k".ä.*\[2 öl ", was sonst zu Fehlern führen würde. Natürlich sind im Code selbst noch zwei zusätzliche Backslashes zum Escapen drin, einmal für das Anführungszeichen und einmal für den Backslash selbst, welche eben nur bei der Notation der Zeichenkette an sich vorhanden sind, also weder bei der Eingabe noch bei einer vorausgegangenen Erfassung des Strings tags in einem vollständigen Programm.

Implizit sind innere Whitespaces Teil des Suchwortes, was durchaus praktisch sein kann, aber bei einer richtigen Suche stören könnte, käme also auf den konkreten Verwendungszweck an. Das wäre jetzt etwa so eine Minimallösung, bei der der Benutzer nicht gleich bloß wegen beliebiger Eingaben mit einem Ausstieg seines Browsers konfrontiert wird. Wie immer natürlich alles ohne Gewähr.

Aber man beachte die False Positives durch \b bei Sonderzeichen innerhalb von Wörtern. Ein Workaround mit fallweisem \B ist sehr umständlich, weil man auch damit weitere False Positives einführt und die behandeln müsste. Es kommt also darauf an, was man als Wortbegrenzung ansieht, nur Whitespaces oder eben jeden Übergang zwischen \w und \W.

Man sieht auch schön, dass es bei Umlauten und Sonderzeichen Probleme gibt, deshalb der seltsame String da oben. Das sind nämlich keine Elemente aus [0-9a-zA-Z_] oder kurz \w. Deshalb wird z.B. "öl" nicht gefunden, weil die Grenze, die mit \b gefunden wird, zwischen den beiden Zeichen liegt. Daher wird "l" gefunden, wenn man explizit danach sucht.

PS
Man kann das auch alleine mit dem String-Objekt machen, also ganz ohne ein "new RegExp".

jabu
24.03.2014, 19:10
Wenn man sich von dem \b bzw. \B verabschiedet und als Separatoren Whitespace sowie Anfang und Ende der Zeichenkette nimmt, ginge etwas in dieser Richtung:

<html>
<head><title>Test</title>
<script type="text/javascript">
<!--
var tags = "-^dfhallo Tag1 +k\". ä.*+ \\[2+ öl+\\[\\-\\[\\]\\/\\{\\}\\(\\)\\*\\+\\?\\.\\\\\\^\\$\\|]+"
//entspricht: -^dfhallo Tag1 +k". ä.*+ \[2+ öl+\[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]+

function add_tags(str) {

str = str.trim();

var escaped = str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
var pattern = new RegExp("(^|\\s)" + escaped + "(\\s|$)");
var isfound = pattern.test(tags);

isfound = isfound || str=="";

if(isfound) {
alert("Gefunden!");
} else {
alert("Nicht Gefunden... Tags: "+tags+"\nString: "+str);
}
}
//-->
</script>
</head>
<body>
<form name="" action="">
<input type="text" name="Eingabe" size="8">
<input type="button" value="Pr&uuml;fe Zeichenkette" onclick="add_tags(this.form.Eingabe.value)">
</body>
</html>
Meinen Geschmack treffen solche "Lösungen" allerdings nicht. Ich würde mindestens einen reservierten Code als Begrenzer vorsehen, welcher bei normaler Eingabe nicht vorkommt. Darauf geprüft würde trotzdem, weil man als User grundsätzlich eingeben kann, was man will. Ist das reservierte Zeichen dennoch enthalten, würde gnadenlos mit Fehlermeldung abgebrochen. Denn ganz gleich, wie man das behandeln würde, käme recht wahrscheinlich etwas anderes heraus, als ein unvorbereiteter User erwarten würde. Denn alles ab dem ersten Begrenzer würde man eh verwerfen, damit nicht zwei Einträge auf einmal entstehen. Und da ich auch von sowas nicht besonders angetan bin, würde ich das alles wohl eher von Anfang an mindestens in ein Array tun und das dann vielleicht mit array.indexOf(item,start) durchsuchen. In einen String konvertieren kann man ja immer noch bedarfsweise. Grundsätzlich sind dumme Funktionen besser als schlaue, also lieber etwas nehmen, was ohne Regular Expressions auskommt, soweit sie nicht gebraucht werden.