2010-11-18 9 views
1

Ich habe eine harte Zeit mit etwas, das wie eine einfache Regex-Aufgabe zu sein scheint. Ich möchte alle href-Links in Text, die Großbuchstaben mit Kleinbuchstaben haben, durch die folgenden Ausnahmen ersetzen.C# Reguläre Ausdrücke suchen und ersetzen Links mit nur Großbuchstaben und entsprechen nicht den Ausschlüssen

Zum Beispiel

href="/image-ZOOM.aspx?UPPERcasE=someThing" Spiel und ersetzen zu

href="/image-zoom.aspx?uppercase=something"

href="/image-coorect.aspx" - würde

nicht überein

Auch wäre es href="javascript:function();" und würde nicht Klein etwas zwischen <% %> Tags auszuschließen.

Zum Beispiel:

href="/images/PDFs/<%=Product.ShortSku %>.pdf" wird in

übersetzt

href="/images/**pdfs**/<%=Product.ShortSku %>.pdf"

habe ich versucht, so etwas wie href="([^"]*[A-Z]+[^"]*)" aber das passt noch Links mit Kleinbuchstaben. Könnten Sie bitte etwas Licht scheinen lassen?

Danke!

+1

Wenn Sie nur in Kleinbuchstaben konvertieren, warum ist es dann von Bedeutung, wenn sie mit Links übereinstimmt, die bereits in Kleinbuchstaben geschrieben sind? Effektiv würde dem sowieso nichts passieren. – mellamokb

+0

Das Muster, das Sie geben, stimmt nicht mit href = "/ image-coorect.aspx" für mich überein. Können Sie Ihren Testcode anzeigen? – mellamokb

+0

Das stimmt, aber wenn ich <% %> innerhalb des Links habe ich nicht wollen, dass es in Kleinbuchstaben konvertiert – Sergey

Antwort

6

Der schwierige Teil ist Ihre <% ... %> Anforderung. Es ist eigentlich ziemlich einfach, wenn Sie jeden Teil der URL in Gruppen aufteilen.

href="/images/PDFs/<%=Product.ShortSku %>.pdf" 
     |_____1_____||__________2_________||_3_| 
  1. Diese Gruppe muss vorhanden sein.
  2. Diese Gruppe ist optional.
  3. Wenn Gruppe 2 nicht vorhanden ist, wird Gruppe 3 nicht vorhanden sein. In diesem Fall stimmt Gruppe 1 mit dem gesamten href-Inhalt überein. Wenn Gruppe 2 existiert, ist Gruppe 3 der Rest des href-Inhalts.

Durch das Verständnis über Sie mit diesem für andere Saiten am Ende:

href="/image-ZOOM.aspx?UPPERcasE=someThing" 
     |________________1_________________| 

ich mit diesem Muster endete die Verwendung von benannten Gruppen macht:

@"href=""(?!javascript:)(?=[^""]*[A-Z])(?<Start>[^""<]+)(?<Special><%[^""]+%>)?(?<End>[^""]*)""" 
  • href="": passt auf href und öffnet double-quote.
  • (?!javascript:): negative Vorausschau JavaScript-Funktionen zu ignorieren.
  • (?=[^""]*[A-Z]): positive Vorausschau, um Großbuchstaben im Inhalt zu finden, um zu kommen. Die [^""]* entspricht einem beliebigen Zeichen, das kein Doppelzitat ist. Dies geschieht, um zu vermeiden, dass das Ende des Inhalts überschritten wird und unbeabsichtigter Inhalt gierig angepasst wird.
  • (?<Start>[^""<]+): Benannte Gruppe, die mit einem beliebigen Zeichen übereinstimmt, solange es keine doppelte Anführungszeichen oder öffnende spitze Klammer ist. Sehen Sie sich die frühere Darstellung an - die Winkelklammerprüfung stellt sicher, dass wir aufhören, wenn <% ... %> Inhalt gefunden wird. Wenn dies nicht der Fall ist, wird das Muster fortgesetzt, bis es auf das schließende Doppelzitat trifft.
  • (?<Special><%[^""]+%>)?: optional benannte Gruppe zu erfassen <% ... %> Inhalt. Das nachgestellte ? markiert diese gesamte Gruppe als optional.
  • (?<End>[^""]*): benannte Gruppe, die mit dem restlichen Inhalt übereinstimmt. Beachten Sie, dass ich * verwende, um es mit null oder mehr Inhalt übereinstimmen. Dies ermöglicht, dass dieser Teil des Musters als eine optionale Übereinstimmung in dem Fall wirkt, in dem die Gruppe nicht existiert.
  • "": Schließen Doppelzitat.

Beispielcode:

string[] inputs = 
{ 
    "href=\"/image-ZOOM.aspx?UPPERcasE=someThing\"", // match 
    "href=\"/image-coorect.aspx\"", // no match, lowercase 
    "href=\"javascript:function();\"", // no match, javascript 
    "href=\"/images/PDFs/<%=Product.ShortSku %>.pDf\"", // bypass <% %> content 
}; 

string pattern = @"href=""(?!javascript:)(?=[^""]*[A-Z])(?<Start>[^""<]+)(?<Special><%[^""]+%>)?(?<End>[^""]*)"""; 

foreach (var input in inputs) 
{ 
    Console.WriteLine("{0,6}: {1}", Regex.IsMatch(input, pattern), input); 
    string result = Regex.Replace(input, pattern, 
         m => "href=\"" 
          + m.Groups["Start"].Value.ToLower() 
          + m.Groups["Special"].Value 
          + m.Groups["End"].Value.ToLower() 
          + "\""); 
    Console.WriteLine("Result: " + result); 
    Console.WriteLine(); 
} 

Dieses eine Lambda anstelle des MatchEvaluator verwendet. Im Wesentlichen rekonstruieren wir die Zeichenfolge und beziehen uns auf die benannten Gruppen, indem wir die Groß-/Kleinschreibung der Gruppen ändern, die wir ändern möchten. Der subtile Schlüssel zu diesem Code ist, dass, wenn eine Gruppe nicht übereinstimmt, wir immer noch darauf verweisen können und es uns einfach einen leeren String geben wird. Auch dies ist möglicherweise nicht offensichtlich aus dem Code, aber wenn eine Übereinstimmung fehlschlägt, wird die ursprüngliche Zeichenfolge unverändert von Regex.Replace zurückgegeben.

+0

Was passiert, wenn Sie Buchstaben haben, die nicht '[A-Z]' sind? – tchrist

+0

@tchrist Das '[A-Z]' wird nur verwendet, um Inhalte mit Großbuchstaben zu vergleichen. Wenn keine vorhanden ist, schlägt die Übereinstimmung fehl und es findet keine Ersetzung statt. Wenn sie existieren, dann stimmt das Muster wirklich mit "[^" "] +" überein, d. H. Alles, was kein Doppelzitat ist. Letztendlich wirkt sich der Aufruf 'ToLower()' auf alle Buchstaben in einer Übereinstimmung aus. –

+0

Wow, vielen Dank Ahmad, sehr informative Antwort und sehr detailliert! Was würden Sie tun, wenn Sie nicht wissen, wie viele Ausschlüsse mit <% %> Sie in Ihren Strings hatten, zum Beispiel wenn href 2 oder 3 Ausdrücke innerhalb <% %> Tags enthält – Sergey

1

verwenden Sie vielleicht die "/ i" Modifikator, stellen Sie sicher, dass Sie nicht "RegexOptions.IgnoreCase"

List<string> list = new List<string>() { 
     "href=\"/image-ZOOM.aspx?UPPERcasE=someThing\"", 
     "href=\"/image-zoom.aspx?uppercase=something\"", 
     "href=\"/image-coorect.aspx\"", 
     "href=\"javascript:function();\"" 
    }; 

    foreach (string l in list) 
    { 
     if (Regex.IsMatch(l, "href=\"([^\"]*[A-Z]+[^\"]*)\"")) 
     { 
      Console.WriteLine(l); 
     } 
    } 

Wird nur Spiel mit: href = "/ image-ZOOM.aspx? UPPERcasE = someThing "

+0

Das ist toll danke, aber wie kann ich <% content %> aus dem Spiel ausschließen? – Sergey

+0

Gott sei Dank URLs dürfen nichts anderes als ASCII sein! (?) – tchrist

1

Ok, ich bin verwirrt. Wenn Sie eine Sammlung von Steuerelementen und/oder Tags auf Ihrer Seite haben, können Sie sie testen, um zu sehen, ob sie Ankertypen sind. Wenn ja, können Sie das href-Attribut vom Tag abrufen und dann href auf href.ToLower setzen. .

Gibt es eine bestimmte Grund, eine Regex zu verwenden, um ein String- und DOM-Parsing-Problem zu lösen? Sieht für mich wie Overkill aus.

+0

+ ∞⁠⁠⁠⁠⁠⁠⁠⁠⁠⁠⁠⁠⁠⁠ – tchrist

+0

ja es gibt einen Grund, ich habe eine alte Lösung mit 2000 Aspx-Dateien und ich muss alle Links Kleinbuchstaben automatisch machen – Sergey

+0

@McLovin ~ So bist du Machen Sie das in Visual Studio dann oder die App? Wenn in der App ein Modul für IIS schreiben. Wenn Sie auf IIS sind, was ist dann wichtig? – jcolebrand

Verwandte Themen