2009-08-20 16 views
4

Betrachten Sie einen Algorithmus, der bestimmen muss, ob eine string Zeichen außerhalb der Whitelist-Zeichen enthält..NET Regex für Whitelist-Zeichen

Die weiße Liste sieht wie folgt aus:

‚-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÖÜáíóúñÑÀÁÂÃÈÊËÌÍÎÏÐÒÓÔÕØÙÚÛÝßãðõøýþÿ

Hinweis: Räume und Apostrophe nötig sind, um in diesem Whitelist aufgenommen werden.

In der Regel ist dies eine statische Methode, die jedoch in eine Erweiterungsmethode konvertiert wird.

private bool ContainsAllWhitelistedCharacters(string input) 
{ 
    string regExPattern="";// the whitelist 
    return Regex.IsMatch(input, regExPattern); 
} 

Überlegungen:

Vielen Dank für die Leistung Kommentare zu allen Beantworter. Leistung ist kein Problem. Qualität, Lesbarkeit und Wartbarkeit ist! Weniger Code = weniger Chance für Defekte, IMO.

Frage:

Was sollte diese weiße Liste RegexMuster sein?

+2

Wenn Sie eine Erweiterungsmethode für 'string' erstellen, wird vorgeschlagen, dass alle Zeichenfolgen einer Whitelist unterliegen, was sie enthalten können und was nicht, aber das stimmt nicht. –

+0

@ 28: Danke für den Kommentar. Ich weiß, dass die Methode für alle "String" -Mitglieder verfügbar sein würde. Es wäre Sache des Entwicklers, weise die Erweiterungsmethode aufzurufen, genau wie bei der Implementierung als Hilfsmethode. –

+0

@ pcampbell: Sie sollten eine unveränderliche Struktur erstellen, die eine Zeichenfolge enthält, von der bekannt ist, dass sie keine fehlerhaften Zeichen enthält (im Konstruktor markiert). Auf diese Weise können Sie im Gegensatz zur Klasse "Path" mit der Zeichenfolge arbeiten, ohne eine O (n) -Prüfung auf ungültige Zeichen durchführen zu müssen. –

Antwort

4

könnte Sie Mustervergleich mit dem folgenden:

^([\-\.a-zA-Z ÇüéâäàåçêëèïîíìÄÅÉæÆôöòûùÖÜáíóúñÑÀÁÂÃÈÊËÌÍÎÏÐÒÓÔÕØÙÚÛÝßãðõøýþÿ]+)$ 

Machen Sie es sich eine Erweiterungsmethode mit:

public static bool IsValidCustom(this string value) 
{ 
    string regExPattern="^([\-\.a-zA-Z ÇüéâäàåçêëèïîíìÄÅÉæÆôöòûùÖÜáíóúñÑÀÁÂÃÈÊËÌÍÎÏÐÒÓÔÕØÙÚÛÝßãðõøýþÿ]+)$"; 
    return Regex.IsMatch(input, regExPattern); 
} 

ich nicht eine einfache Möglichkeit denken kann eine wartbare Bereich mit erweiterten Zeichen zu tun da die Reihenfolge der Charaktere nicht offensichtlich ist.

+0

Achtung bei Zeichensätzen. – Havenard

+0

Ich denke, das obige Muster erfordert eine kleine Optimierung, um leere Werte zuzulassen. Verwenden Sie auch die integrierte Zeichenklasse "\ w", anstatt das Alphabet aller unterstützten Sprachen aufzulisten. Das bringt Unterstriche und Ziffern mit sich, die dann eine zweite RegEx ausschließen müssten, aber würde eine Menge möglicher Wartung auf der Straße sparen, um die Charakterklasse neu zu erfinden. – richardtallent

+1

Ich habe es getestet und es funktioniert für Räume. Es ist eine hartcodierte Liste von Werten, der Raum ist nach dem Z enthalten. Die einzigen Bereiche sind die Zeichen von a-z und A-Z – Kelsey

5

Warum muss es eine Regex sein?

private bool ContainsAllWhitelistedCharacters(string input) 
{ 
    string whitelist = "abcdefg..."; 
    foreach (char c in input) { 
    if (whitelist.IndexOf(c) == -1) 
     return false; 
    } 
    return true; 
} 

Keine Notwendigkeit, gerade in regulären Ausdrücke zu springen, wenn Sie nicht sicher sind, wie die, die Sie implementieren müssen, und Sie haben profilieren nicht, dass Code-Abschnitt und fanden heraus, Sie die zusätzliche Leistung benötigen.

+0

Umm ... das funktioniert nicht so warum alle upvotes? Es wird nicht abgefangen, wenn ungültige Zeichen in der Zeichenfolge enthalten sind. – Kelsey

+0

Danke Mark. Leider gibt dieser Vorschlag 'IndexOfAny' keine nicht-weiß markierten Zeichen wie '_' oder '5' aus. –

+0

Ja, das habe ich gerade gemerkt und es rausgeholt - das hätte eigentlich keine Upvotes bekommen sollen. Niemand, der es upvoted hat, hat es sogar gelesen: X –

0

Ich weiß nicht, wie die Regex Backend implementiert ist, aber es könnte die effizienteste sein, die noch folgende für nichts außer Ihrer Liste entsprechen:

private bool ContainsAllWhitelistedCharacters(string input) 
{ 
    Regex r = new Regex("[^ your list of chars ]"); 
    return !r.IsMatch(test) 
} 
+6

Doppelte Negative sind nicht verwirrend. –

+0

Ich stimme zu, ich schlug vor, es auf diese Weise zu tun * vorausgesetzt, es ist eine effizientere Regex in C#. Weiß jemand, ob das stimmt oder nicht? Ich bin an der Antwort interessiert. –

0

Beachten Sie, dass ich nicht empfehlen, es sei denn dies Leistung ist wirklich ein Problem, aber ich dachte, ich möchte darauf hinweisen, dass auch die Regex einschließlich Vorkompilieren, Sie schneller ziemlich viel zu tun:

vergleichen:

static readonly Regex r = new Regex(
    @"^(['\-\.a-zA-Z ÇüéâäàåçêëèïîíìÄÅÉæÆôöòûùÖÜáíóúñÑ"+ 
    "ÀÁÂÃÈÊËÌÍÎÏÐÒÓÔÕØÙÚÛÝßãðõøýþÿ]+)$"); 

public bool IsValidCustom(string value) 
{ 
    return r.IsMatch(value); 
} 

mit:

private bool ContainsAllWhitelistedCharacters(string input) 
{ 
    foreach (var c in input) 
    { 
     switch (c) 
     { 
      case '\u0020': continue; 
      case '\u0027': continue; 
      case '\u002D': continue; 
      case '\u002E': continue; 
      case '\u0041': continue; 
      case '\u0042': continue; 
      case '\u0043': continue; 
      case '\u0044': continue; 
      case '\u0045': continue; 
      case '\u0046': continue; 
      case '\u0047': continue; 
      case '\u0048': continue; 
      case '\u0049': continue; 
      case '\u004A': continue; 
      case '\u004B': continue; 
      case '\u004C': continue; 
      case '\u004D': continue; 
      case '\u004E': continue; 
      case '\u004F': continue; 
      case '\u0050': continue; 
      case '\u0051': continue; 
      case '\u0052': continue; 
      case '\u0053': continue; 
      case '\u0054': continue; 
      case '\u0055': continue; 
      case '\u0056': continue; 
      case '\u0057': continue; 
      case '\u0058': continue; 
      case '\u0059': continue; 
      case '\u005A': continue; 
      case '\u0061': continue; 
      case '\u0062': continue; 
      case '\u0063': continue; 
      case '\u0064': continue; 
      case '\u0065': continue; 
      case '\u0066': continue; 
      case '\u0067': continue; 
      case '\u0068': continue; 
      case '\u0069': continue; 
      case '\u006A': continue; 
      case '\u006B': continue; 
      case '\u006C': continue; 
      case '\u006D': continue; 
      case '\u006E': continue; 
      case '\u006F': continue; 
      case '\u0070': continue; 
      case '\u0071': continue; 
      case '\u0072': continue; 
      case '\u0073': continue; 
      case '\u0074': continue; 
      case '\u0075': continue; 
      case '\u0076': continue; 
      case '\u0077': continue; 
      case '\u0078': continue; 
      case '\u0079': continue; 
      case '\u007A': continue; 
      case '\u00C0': continue; 
      case '\u00C1': continue; 
      case '\u00C2': continue; 
      case '\u00C3': continue; 
      case '\u00C4': continue; 
      case '\u00C5': continue; 
      case '\u00C6': continue; 
      case '\u00C7': continue; 
      case '\u00C8': continue; 
      case '\u00C9': continue; 
      case '\u00CA': continue; 
      case '\u00CB': continue; 
      case '\u00CC': continue; 
      case '\u00CD': continue; 
      case '\u00CE': continue; 
      case '\u00CF': continue; 
      case '\u00D0': continue; 
      case '\u00D1': continue; 
      case '\u00D2': continue; 
      case '\u00D3': continue; 
      case '\u00D4': continue; 
      case '\u00D5': continue; 
      case '\u00D6': continue; 
      case '\u00D8': continue; 
      case '\u00D9': continue; 
      case '\u00DA': continue; 
      case '\u00DB': continue; 
      case '\u00DC': continue; 
      case '\u00DD': continue; 
      case '\u00DF': continue; 
      case '\u00E0': continue; 
      case '\u00E1': continue; 
      case '\u00E2': continue; 
      case '\u00E3': continue; 
      case '\u00E4': continue; 
      case '\u00E5': continue; 
      case '\u00E6': continue; 
      case '\u00E7': continue; 
      case '\u00E8': continue; 
      case '\u00E9': continue; 
      case '\u00EA': continue; 
      case '\u00EB': continue; 
      case '\u00EC': continue; 
      case '\u00ED': continue; 
      case '\u00EE': continue; 
      case '\u00EF': continue; 
      case '\u00F0': continue; 
      case '\u00F1': continue; 
      case '\u00F2': continue; 
      case '\u00F3': continue; 
      case '\u00F4': continue; 
      case '\u00F5': continue; 
      case '\u00F6': continue; 
      case '\u00F8': continue; 
      case '\u00F9': continue; 
      case '\u00FA': continue; 
      case '\u00FB': continue; 
      case '\u00FC': continue; 
      case '\u00FD': continue; 
      case '\u00FE': continue; 
      case '\u00FF': continue;   
     } 
     return false;  
    } return true; // empty string is true  
} 

In sehr schnellen Test auf einem Korpus von Wörtern mit etwa 60% Erfolgsquote I etwa um einen Faktor von 8 Geschwindigkeit bekommen mit diesem Ansatz auf.

Es ist nicht so viel weniger lesbar als die Regex ohne die Escape-Zeichen entweder!