Gernot Back: Sonderzeichen abfangen - Nur die guten ins Töpfchen

Hallo an alle,

ich suche eine Javascriptlösung, um Sonderzeichen abzufangen, die in einer URI Probleme bereiten.

Hintergrund ist, dass sich auf der "Clanseite" ;-), an der ich gerade arbeite, Unterclans gründen können und aus dem gewählten Namen des Unterclans eine für alle Browser taugliche Internetadresse generiert werden soll, unter der man diesen Unterclan dann zukünftig direkt erreichen kann. Das Ganze soll lesbar und einprägsam sein, also ohne Encode-Geschichten!

Der von mir gegründete Unterclan heißt z.B. "Die Erdbeeren-Diätbären"

Das System der Hauptclanseite macht mir da serverseitig schon mal den Vorschlag, dass mein Unterclan zukünftig direkt über folgende Adresse erreichbar sein soll.

http://www.meinLieberClan.de/Die-Erdbeeren-Diaetbaeren

Nun soll mir als Gründer des Unterclans aber auch die Möglichkeit gegeben werden, diese Adresse zu ändern.

Ich hätte das z.B. lieber alles klein geschrieben und in einem Wort.

Auch da würde es spätestens serverseitig wieder abgefangen, wenn ich nun doch wieder ein Sonderzeichen eingäbe. Wir hätten es nun aber gerne so, dass mir da auch clientseitig und vor dem Abschicken das System einen Hinweis gäbe, sobald ich ein unerlaubtes Zeichen eingebe.

Ich habe auch bereits eine Lösung gefunden, die mir allerdings recht umständlich erscheint. Dabei speichere ich alle ASCII-Codes unerwünschter Zeichen in ein Array und falls document.onkeypress der Keycode mit einem dieser Tabuzeichen übereinstimmen sollte, bekomme ich eine Meldung und die Annahme des Zeichens in ein bestimmtes Eingabefeld (im Beispiel das zweite) wird verweigert.

Ich habe es auch mit regulären Ausdrücken versucht. Das Problem dabei: Die erste Pechmarie(Sonderzeichen) fällt mir jeweils in den Brunnen und eine folgende Goldmarie(kein Sonderzeichen) wird aber dann auch gleich mit dem Bade ausgeschüttet(die macht zwar dann ihre vorangegangene böse Schwester im Eingabefeld unschädlich, wird selbst aber auch nicht angenommen).

Ich habe es mit den Eventhandlern onkeypress, onkeydown und onkeyup versucht. Die beiden letzteren sind aber eher noch ungünstiger.

Gibt es wirklich keine Lösung mit regulären Ausdrücken?

Gruß Gernot

Nachfolgend mein Code, wo ihr durch Umkommentieren mal meine Lösung und meinen gescheiterten Versuch testen könnt:

  
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">  
<html>  
<head>  
<title>Tasten sperren</title>  
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />  
</head>  
<body>  
<form name="meinForm" action="" method="" target="">  
<textarea name="meineArea" cols="20" rows="5"></textarea><br />  
<input type="Text" name="eing" value="" size="20" onblur="[code lang=javascript]flag=false
~~~" onfocus="`flag=true`{:.language-javascript}" />  
</form>  
<script type="text/javascript">  
~~~javascript
  
var flag;  
  
var tabu = new Array();  
  
for (i=0; i<8 ; i++ ) {  
  tabu[i]=i;  
}  
// 8: Backspace  
for (i=9; i<45 ; i++ ) {  
  tabu.push(i);  
}  
// 45: Minuszeichen  
for (i=46; i<48 ; i++ ) {  
  tabu.push(i);  
}  
// 48-57: Dezimalziffern  
for (i=58; i<65 ; i++ ) {  
  tabu.push(i);  
}  
// 65-90: Großbuchstaben  
for (i=91; i<94 ; i++ ) {  
  tabu.push(i);  
}  
// 95: Unterstrich  
tabu.push(96);  // Hochkomma  
// 97-122: Kleinbuchstaben  
for (i=123; i<256 ; i++ ) {  
  tabu.push(i);  
}  
  
function filtern1 (e) {  
  var keyCode=(e)? e.which :event.keyCode;  
  for (i=0; i< tabu.length; i++) {  
    if(flag&&(keyCode == tabu[i])){  
      alert('Sonderzeichen!');  
      return false;  
    }  
  }  
}  
  
var suche = /\W/;  
  
function filtern2 () {  
  kette = document.forms.meinForm.eing.value;  
  if(flag&&suche.test(kette)){  
    document.forms.meinForm.eing.value = kette.replace(suche,"");  
    return false;  
  }  
}  
document.onkeypress=filtern1;  
//document.onkeypress=filtern2;

</script>
</body>
</html>[/code]

  1. Auf den ersten Blick werden bei Deinem Beispielskript die Unicode-Nummern für die Bereiche a-z, A-Z, 0-9 und einige Sonderzeichen erlaubt. Ist doch okay, wenn es seinen Zweck erfüllt.

    1. Hallo Kim,

      Ist doch okay, wenn es seinen Zweck erfüllt.

      Klar, wenn es in allen Browsern läuft und auch mit älteren Betriebsystemen keine Probleme macht, ist das OK, nur kommt es mir halt doch etwas umständlich vor, dass ich meinem Computer und dem der Nutzer bei jedem Tastendruck, solange ich mich in dem bewussten Eingabefeld befinde, jeweils knapp 200 If-Abfragen zumute. Wenn sich das vermeiden ließe, würde ich das natürlich gerne tun.

      Gruß Gernot

  2. Hallo,

    ich suche eine Javascriptlösung, um Sonderzeichen abzufangen, die in einer URI Probleme bereiten.

    http://www.meinLieberClan.de/Die-Erdbeeren-Diaetbaeren

    Dabei speichere ich alle ASCII-Codes unerwünschter Zeichen in ein Array und falls document.onkeypress der Keycode mit einem dieser Tabuzeichen übereinstimmen sollte, bekomme ich eine Meldung und die Annahme des Zeichens in ein bestimmtes Eingabefeld (im Beispiel das zweite) wird verweigert.

    Keine schlechte Idee, den Event abzufangen. Ein guter Ansatz an sich.

    Ich habe es auch mit regulären Ausdrücken versucht. Das Problem dabei: Die erste Pechmarie(Sonderzeichen) fällt mir jeweils in den Brunnen und eine folgende Goldmarie(kein Sonderzeichen) wird aber dann auch gleich mit dem Bade ausgeschüttet(die macht zwar dann ihre vorangegangene böse Schwester im Eingabefeld unschädlich, wird selbst aber auch nicht angenommen).

    Verstehe nicht ganz, was du meinst. Prüfe halt das eingegebene Zeichen für sich anhand eines passenden Regulären Ausdrucks?

    Rausschneiden bei der Eingabe:

      
    var erlaubt = /\u0008|\u002D|[\u0030-\u0039]|[\u0041-\u005A]|\u005F|[\u0061-\u007A]/;  
    function filtern (e) {  
     for (var i = 0; i < str.length; i++) {  
      if (!erlaubt.test(str.charAt(i))) {  
       // alert(str.charAt(i) + " nicht erlaubt!");  
       str = str.substring(0, i) + str.substr(i + 1);  
      }  
     }  
     document.forms.meinForm.elements.eing.value = str;  
    }  
    document.onkeypress = filtern;  
    
    

    Problem: Der Event feuert, bevor das Zeichen ins Feld geschrieben wurde. Das ist an sich korrekt und in anderen Zusammenhängen nützlich.

    Also wählen wir deine Methode:

    var focussed = false;  
    function erlaubt (c) {  
     return ((c == 8) || (c == 45) || (c >= 48 && c <= 57) || (c >= 65 && c <= 90) || (c == 95) || (c >= 97 && c <= 122));  
    }  
    function filtern (e) {  
     var keyCode = e ? e.which : event.keyCode;  
     // alert(keyCode + " " + erlaubt(keyCode));  
     if (focussed && !erlaubt(keyCode)) {  
      // alert('Sonderzeichen!');  
      if (e.preventDefault)  
       e.preventDefault();  
      return false;  
     }  
    }  
    document.onkeypress = filtern;
    

    Das funktioniert prinzipiell. Wo war jetzt die Schwierigkeit? ;) Deine Blacklist war ja fast schwieriger zu implementieren.

    Mathias

    1. if (e.preventDefault)

      e.preventDefault();
      return false;

        
        
      Der Vollständigkeit halber:  
      ~~~javascript
        
      if (e && e.preventDefault)  
         e.preventDefault();  
      else if (window.event)  
         window.event.returnValue = false;  
      return false; // sollte eigentlich unnötig sein, kann aber auch alleine stehen ;-)  
      
      
    2. var erlaubt = /\u0008|\u002D|[\u0030-\u0039]|[\u0041-\u005A]|\u005F|[\u0061-\u007A]/;

      Hilfe, wie bin ich denn darauf gekommen? So viel verständlicher, eine Zeichenklasse reicht, dort werden die erlaubten Zeichen bzw. Zeichenbereiche aufgelistet:
      [code lang=javascript]var erlaubt = /[\u0008-0-9A-Z_a-z]/;

        
      
      > ~~~javascript
      
      function filtern (e) {  
      
      >  for (var i = 0; i < str.length; i++) {  
        
      var str = document.forms.meinForm.elements.eing.value;  
        
      
      >   if (!erlaubt.test(str.charAt(i))) {  
      >    // alert(str.charAt(i) + " nicht erlaubt!");  
      >    str = str.substring(0, i) + str.substr(i + 1);  
      >   }  
      >  }
      
      
    3. Hallo molily,

      schönen Dank, dass du mir auf die Sprünge geholfen hast: das sind ja jetzt schon deutlich weniger If-Abfragen:

      var focussed = false;

      function erlaubt (c) {
      return ((c == 8) || (c == 45) || (c >= 48 && c <= 57) || (c >= 65 && c <= 90) || (c == 95) || (c >= 97 && c <= 122));
      }
      function filtern (e) {
      var keyCode = e ? e.which : event.keyCode;
      // alert(keyCode + " " + erlaubt(keyCode));
      if (focussed && !erlaubt(keyCode)) {
        // alert('Sonderzeichen!');
        if (e.preventDefault)
         e.preventDefault();
        return false;
      }
      }
      document.onkeypress = filtern;

        
      Ich weiß aber noch nicht so ganz, ob ich deine Aussage zu Regulären Ausdrücken, zumal du ja dann auch noch einige Schönheitskorrekturen nachgeschoben hast, jetzt so interpretieren soll, dass dieser Ansatz ohnehin von vornherein zum Scheitern verurteilt ist:  
        
      
      > Problem: Der Event feuert, bevor das Zeichen ins Feld geschrieben wurde. Das ist an sich korrekt und in anderen Zusammenhängen nützlich.  
      > Also wählen wir deine Methode ...  
        
      Problem ist ja also offensichtlich, dass das Kind (Zeichen) erst einmal in den Brunnen (das Inputfeld) fallen muss, bevor ich seinen Wert auslesen kann.  
        
      Könnte man nicht aber auch aus dem abgefangenen numerischen keyCode den Wert der Taste als Character zurückrechnen und darauf dann einen schlichten Suchausdruck wie /\w/ über die test()-Methode anwenden und auch damit gegebenenfalls die Standardaktion (das Schreiben des entsprechenden Zeichens ins Eingabefeld) von vornherein unterbinden?  
        
      Gruß Gernot
      
      1. Hallo,

        function erlaubt (c) {
        return ((c == 8) || (c == 45) || (c >= 48 && c <= 57) || (c >= 65 && c <= 90) || (c == 95) || (c >= 97 && c <= 122));
        }

        Ich weiß aber noch nicht so ganz, ob ich deine Aussage zu Regulären Ausdrücken, zumal du ja dann auch noch einige Schönheitskorrekturen nachgeschoben hast, jetzt so interpretieren soll, dass dieser Ansatz ohnehin von vornherein zum Scheitern verurteilt ist:

        Nicht, weil er mit regulären Ausdrücken arbeitet, sondern deshalb:

        Problem ist ja also offensichtlich, dass das Kind (Zeichen) erst einmal in den Brunnen (das Inputfeld) fallen muss, bevor ich seinen Wert auslesen kann.

        Könnte man nicht aber auch aus dem abgefangenen numerischen keyCode den Wert der Taste als Character zurückrechnen und darauf dann einen schlichten Suchausdruck wie /\w/ über die test()-Methode anwenden

        Ja, aber wo besteht der Vorteil zur Methode mit einer direkten Prüfung von keyCode über den genannten Ausdruck? Weil man den regulären Ausdruck einfacher und lesbarer notieren kann?

        und auch damit gegebenenfalls die Standardaktion (das Schreiben des entsprechenden Zeichens ins Eingabefeld) von vornherein unterbinden?

        Ja, das Abfangen des keypress-Events funktioniert unabhängig von der Vergleichsmethode.

        Mathias

        1. Könnte man nicht aber auch aus dem abgefangenen numerischen keyCode den Wert der Taste als Character zurückrechnen und darauf dann einen schlichten Suchausdruck wie /\w/ über die test()-Methode anwenden

          Ja

          /\w/ ist anscheinend nicht so sinnig. Erstens sieht Mozilla Umlaute als Wort-Zeichen an, zweitens muss mindestens der Backspace genannt werden.

          var focussed = false;  
          var namensmuster = /[\u0008A-Za-z0-9\-_]/;  
          function erlaubt (code) {  
           var character = String.fromCharCode(code);  
           return (namensmuster.test(character));  
          }  
          function filtern (e) {  
           var keyCode = e ? e.which : event.keyCode;  
           if (focussed && !erlaubt(keyCode))  
            return false;  
          }  
          document.onkeypress = filtern;
          

          Mathias