Fetstil Fetstil Kursiv Understrykning linje färgläggning tabellverk Punktlista Nummerlista Vänster Centrerat högerställt Utfyllt Länk Bild htmlmode
  • Forum & Blog
    • Forum - översikt
      • .Net
        • asp.net generellt
        • c#
        • vb.net
        • f#
        • silverlight
        • microsoft surface
        • visual studio .net
      • databaser
        • sql-server
        • databaser
        • access
        • mysql
      • mjukvara klient
        • datorer och komponenter
        • nätverk, lan/wan
        • operativsystem
        • programvaror
        • säkerhet, inställningar
        • windows server
        • allmänt
        • crystal reports
        • exchange/outlook
        • microsoft office
      • mjukvara server
        • active directory
        • biztalk
        • exchange
        • linux
        • sharepoint
        • webbservers
        • sql server
      • appar (win/mobil)
      • programspråk
        • c++
        • delphi
        • java
        • quick basic
        • visual basic
      • scripting
        • asp 3.0
        • flash actionscript
        • html css
        • javascript
        • php
        • regular expresssion
        • xml
      • spel och grafik
        • DirectX
        • Spel och grafik
      • ledning
        • Arkitektur
        • Systemutveckling
        • krav och test
        • projektledning
        • ledningsfrågor
      • vb-sektioner
        • activeX
        • windows api
        • elektronik
        • internet
        • komponenter
        • nätverk
        • operativsystem
      • övriga forum
        • arbete karriär
        • erbjuda uppdrag och tjänster
        • juridiska frågor
        • köp och sälj
        • matematik och fysik
        • intern information
        • skrivklåda
        • webb-operatörer
    • Posta inlägg i forumet
    • Chatta med andra
  • Konto
    • Medlemssida
    • Byta lösenord
    • Bli bonsumedlem
    • iMail
  • Material
    • Tips & tricks
    • Artiklar
    • Programarkiv
  • JOBB
  • Student
    • Studentlicenser
  • KONTAKT
    • Om pellesoft
    • Grundare
    • Kontakta oss
    • Annonsering
    • Partners
    • Felanmälan
  • Logga in

Hem / Artiklar / Titel på artikeln

Case insensitive replace och tillämpningar

Postad 2004-05-20 av Herbjörn Wilhelmsen i sektionen ASP.NET, C#, Okategoriserat med 1 Kommentarer | Läst av: 207640, Betyg: 90%

Förord

Standard Replace i string-klassen är case sensitive. På (nästan ren) svenska betyder det att string-klassens ersättningsmetod är skriftlägeskänslig, dvs ser stor och liten bokstav som olika bokstäver. Detta kan givetvis bli ett problem om man har behov av att byta ut text oberoende av om texten är skriven med stora eller små bokstäver. På nätet kan man hitta ett flertal lösningar på detta problem. Här presenteras en lite annorlunda lösning som har ett antal fördelar jämfört med de andra lösningarna som diskuteras. Exempel på tillämpningar är att skydda ditt system mot potentiellt farliga ord och att byta ut vissa ord mot bilder.
Innehåll
  » Ordförklaring
  » Replace
  » Case insensitive replace
  » Existerande lösningar
  » En ny lösning
  » En case insensitive Replace-metod
  » Tillämpningar
  » Konklusion
  » Ladda ner koden
  » Resurser


Ordförklaring

För att göra artikeln lättare att läsa kommer jag använda mig av följande ord:
oldValue – den delen av en string som du vill ersätta
newValue – den delen av en string som du vill ersätta oldValue med
expression – en string som du vill ersätta ut delar av


Replace

Att ersätta delar av en text (replace) är mycket enkelt i .NET. Eftersom .NET är objektorienterat kommer den vane objektorienteraren hitta replace-metoden precis där den hör hemma: I string-klassen. Ett exempel:

C#

string myString = "Detta är en av dina strängar";
myString = myString.Replace("dina","mina");


VB.NET

Dim myString As String = "Detta är en av dina strängar"
myString = myString.Replace("dina", "mina")


Efter att replace-metoden körts kommer myString att innehålla texten "Detta är en av mina strängar". En intressant detalj i sammanhanget är att man måste skriva
...
C#

myString = myString.Replace("dina","mina");

VB.NET

myString = myString.Replace("dina","mina")

...
för att koden skall fungera. Detta beror på att en string i .NET inte kan förändras, den är sk Immutable. Om du vill förändra innehållet i en string-variabel måste du helt enkelt skapa en ny string som sedan sparas i din variabel. Replace-metoden skapar och returnerar alltså ett nytt string-objekt som innehåller samma text som myString, med vissa värden utbytta förstås.


Case insensitive replace

När man vill åstadkomma en skriftlägesokänslig ersättning blir det lite svårare. Anledningen till att denna artikel existerar är att skriftlägesokänslig ersättning inte finns implementerat i string-klassen per idag. För att illustrera problemet ytterligare har jag gjort en liten lista på vad vi måste göra för att åstadkomma önskat resultat i vårt exempel ovan oberoende av skriftläget i ordet ”dina”. Vi måste köra Replace på myString med alla de ord som jag skrivit in i listan nedan:

dina
Dina
dIna
diNa
dinA
DIna
DiNa
DinA
diNA
dInA
…(och några ord till)


Ärligt talat blir jag lite trött bara av att skriva en sådan lista. Jag tror att de flesta håller med om att det i praktiken är omöjligt att ta hand om alla fall av stora och små bokstäver genom att använda skriftlägesokänslig ersättning. Iallafall om man vill byta ut mer än ett ganska kort ord (vilket är rätt så tråkigt det också!). Så det vi behöver är en metod som byter ut en text - oberoende av dess kombination med stora och små bokstäver – med en annan text. Det kan väl inte vara så svårt att få till? Helt rätt, det är inte så svårt att få till, ett flertal lösningar finns runt på Internet på olika tutorials, forum, utvecklarsiter etc. Nedan tittar jag lite på några av dem.


Existerande lösningar

Jag vet inte om jag har sett alla lösningarna som har publicerats på nätet men här är iallafall några av dom:


  • Loop-lösningen
    Tanken bakom denna lösningen är att man först tillverkar en version av sitt expression och oldValue som är helt och hållet skrivet med små (alternativt stora) bokstäver. Man har då fått ”skriftlägesokänsliga versioner” av expression och oldValue. Sedan gör man en loop med de skriftlägesokänsliga versionerna som för varje gång man hittar en oldValue i expression gör en ny version av expression som baseras på det orginala expression samt newValue.

  • Den rekursiva lösningen
    Tanken bakom denna lösning är nästan exakt densamma som loop-lösningen. Om man hittar en skriftlägesokänslig version av oldValue i den skriftlägesokänsliga versionen av expression bygger man en ny version av expression och returnerar därefter ett metodanrop till samma metod (Replace) med den nya expression som parameter. När man inte hittar oldValue i expression har allt bytts ut och man returnerar expression.

  • Reguljärt uttryck mönster-lösningen
    Tanken bakom denna lösning är rätt så annorlunda jämfört med de två andra. För att förstå lösningen krävs att man kan lite om Regular Expressions (reguljära uttryck). Enkelt sagt är ett reguljärt uttryck inte en vanlig text men ett mönster. I mönstret kan man ha bokstäver, siffror och andra tecken. Detta mönster kan användas till att hitta en teckenkombination i en text (och en massa andra saker…). För att lösa vårt problem konstruerar man ett mönster som kan hitta oldValue oberoende av skriftläge.

    I reguljära uttryck finns något som kallas Character classes (bokstavsklasser). En bokstavsklass som matchar bokstaven ’A’ oberoende av skriftläge ser ut så här : ”[aA]”. Denna klassen kommer hitta alla ‘a’ och ‘A’ i en text. Ett reguljärt uttryck som hittar ”dina” oberoende av skriftläge ser ut så här: “[dD][iI][nN][aA]”. När man väl har skapat ett reguljärt uttryck skickar man med expression, det reguljära uttrycket och newValue till Replace-metoden i RegEx-klassen som sedan returnerar ett string-objekt.


Enligt min ödmjuka åsikt är Reguljärt uttryck mönster-lösningen den bästa av lösningarna ovan. Ytterligare en av mina ödmjuka åsikter är att ingen av dessa lösningnar är riktigt tillfredsställande. Jag har därför hittat på en annan lösning som är baserad på “Reguljärt uttryck mönster-lösningen”. Jag kallar lösningen Reguljärt uttryck-lösningen…


En ny lösning

I grund och botten är denna lösning densamma som reguljärt uttryck monster-lösningen, fast utan mönstret! En lite mera noggrann inspektion av Replace-metoden i RegEx-klassen visar att en av dess överlagrade versioner kan ta emot en parameter som kallas options och är av typen RegexOptions (en enum). Valet RegexOptions.IgnoreCase beskrivs så här på MSDN: ” Specifies case-insensitive matching.”

Detta innebär att vi kan lämna med ett reguljärt uttryck och tala om för metoden att den skall hitta detta monster oberoende av skriftläge. Det reguljära uttrycket blir i vårt fall mycket enkelt: oldValue, utan några som helst ändringar! Kodsnutten nedan visar hur enkelt det är att implementera skriftlägesokänslig ersättning med den nya lösningen:
C#

expression = Regex.Replace(
expression,
oldValue,
newValue,
RegexOption.IgnoreCase);

VB.NET

expression = Regex.Replace( _
expression, _
oldValue, _
newValue, _
RegexOption.IgnoreCase)

Och det är allt! Inga loopar, inga rekursiva anrop, inga reguljära uttryck att bygga etc. Varför jag föredrar denna lösningen? Jag har i grund och botten tre orsaker:

  • Mindre kod
    Mindre kod betyder att risken för buggar reduceras (OK jag erkänner, jag har gjort ett misstag eller två i min kod förut :)

  • .NET Framework (plattformen .NET) utnyttjas i högre grad
    Detta är en mycket stor fördel eftersom plattformen hela tiden utvecklas och förbättras av Microsoft. Detta innebär att kodens prestanda kan ökas när vi använder nyare versioner av .NET Framework. För att åstadkomma detta behöver vi varken ändra koden eller bygga/kompilera om projektet!

  • Prestanda
    I vissa fall är det detta som betyder mest. I vårt fall handlar det om att utveckla en metod som skall återanvändas om och om igen, så i detta fall är prestanda rätt så betydelsefullt. Enligt ett enkelt test jag gjort med en text på ca 40.000 ord så är min lösning ca 3 gånger snabbare än den näst snabbaste metoden som är reguljärt uttryck mönster-lösningen. Den var i sin tur ca 17 gånger snabbare än loop-lösningen som igen var ca 5 gånger snabbare än den rekursiva lösningen.



En case insensitive Replace-metod

Hur skall vi då implementera en case insensitive Replace-metod? Det finns några saker att tänka på. Borde man göra en ny string-klass som har en överlagrad Replace-metod? Eller göra en klassmetod (static(C#)/Shared(VB.NET)) som tar emot inte bara oldValue och newValue men också expression? Borde vi göra en metod som kan hantera både skriftlägesokänslig och skriftlägeskänslig ersättning? Jag har några förslag:

Att göra en ny string-klass blir något svårt eftersom man inte kan ärva från string-klassen. string-klassen har en hel del metoder som vi i så fall får implementera, och klassen kan komma att ändras i framtiden i nya .NET Framework-versioner. Det senare innebär att om vi vill att vår egna string-klass skall klara av allt som System.string klarar av kan vi behöva modifiera klassen om och om igen. Jag föreslår alltså att göra en static/Shared metod. Skall metoden klara av skriftlägesokänslig och skriftlägeskänslig ersättning? Programmeraren kan ju välja vilken metod han eller hon vill anropa. Även om vi har en metod som kan hantera båda fallen så kan ju programmeraren välja att anropa string-klassens metod för skriftlägeskänslig ersättning. Så varför inte ge programmeraren valet? Min implementation ser ut så här:
C#

public static string Replace(string expression,string oldValue, string newValue, bool caseSensitive) {
string replaced;
if (caseSensitive) {
replaced = expression.Replace(oldValue,newValue);
}
else {
replaced = Regex.Replace(expression, oldValue, newValue, RegexOptions.IgnoreCase);
}
return replaced;
}

VB.NET

Public Shared Function Replace(ByVal expression As String, ByVal oldValue As String, _
ByVal newValue As String, ByVal caseSensitive As Boolean) As String
Dim replaced As String
If caseSensitive Then
replaced = expression.Replace(oldValue, newValue)
Else
replaced = Regex.Replace(expression, oldValue, newValue, RegexOptions.IgnoreCase)
End If
Return replaced
End Function



Tillämpningar

Vad kan vi använda denna nya funktionalitet till? Jag har två exempel: Ta bort potentiellt farliga ord från en text och byta ut vissa ord i en text på en webbsida mot bilder. Båda dessa tillämpningarna kräver att man använder Replace på samma text ett antal gånger med olika oldValues och newValues. Jag har därför skrivit ytterligare en metod som tar emot många parametrar för oldValue och newValue. Vid anrop till denna metod skall parametern oldAndNewValues ha värden enligt detta mönstret: ”oldValue|newValue”, t.ex. ”dina|mina”.
C#

public static string MultipleReplace(string expression,bool caseSensitive,params string[] oldAndNewValues) {
string replaced = expression;
string[] oldAndNew;
foreach(string oldAndNewValue in oldAndNewValues) {
oldAndNew = oldAndNewValue.Split('|');
replaced = Replace(replaced,oldAndNew[0],oldAndNew[1],caseSensitive);
}
return replaced;
}

VB.NET

Public Shared Function MultipleReplace(ByVal expression As String, ByVal caseSensitive As Boolean, ByVal ParamArray oldAndNewValues() As String) As String
Dim replaced As String = expression
Dim oldAndNewValue As String
Dim oldAndNew() As String
For Each oldAndNewValue In oldAndNewValues
oldAndNew = oldAndNewValue.Split("|")
replaced = Replace(replaced, oldAndNew(0), oldAndNew(1), caseSensitive)
Next
Return replaced
End Function


Nyckelordet params(C#)/ParamArray(VB.NET) gör att oldAndNewValues blir en parameter-array. Detta innebär att man antingen kan anropa metoden med en string[](C#)/String()(VB.NET) som innehåller ett antal string-objekt med oldValue|newValue, eller skriva in så många oldValue|newValue string man vill som parametrar till metoden. Utifrån detta har jag (mycket enkelt) skrivit en metod som eliminerar potentilelt farliga ord (rätt så många script- och programmeringsspråk är case insensitive) från en text :
C#

public static string ReplaceDangerousWords(string s) {
//add any number of potentially dangerous words to the parameter list
return MultipleReplace(s,false,
"object|object",
"script|script",
"applet|applet");
}

VB.NET

Public Shared Function ReplaceDangerousWords(ByVal s As String) As String
'add any number of potentially dangerous words to the parameter list
Return MultipleReplace(s, False, _
"object|object", _
"script|script", _
"applet|applet")
End Function

Lika enkelt är det att skriva en metod som lägger in bilder i en text (inte alla är lika noga när det gäller att använda små och stora bokstäver som programmerare SMiley):
C#

public static string InsertImagesInText(string s) {
//add any number of image replacements to the parameter list
return MultipleReplace(s,true,
" smiley | ",
" ulgy | ",
" .net | ");
//don't replace parts of a web-address:
//include a space before and after words
}

VB.NET

Public Shared Function InsertImagesInText(ByVal s As String) As String
'add any number of image replacements to the parameter list
Return MultipleReplace(s, False, _
" smiley | ", _
" ugly | ", _
" .net | ")
'don't replace parts of a web-address:
'include a space before and after words
End Function



Konklusion

Att kunna utföra case insensitive Replace på en text är ibland mycket viktigt. I .NET är case insensitive Replace inte implementerat per default i string-klassen, men är ändå rätt så lätt att åstadkomma.


Ladda ner koden

Klicka på bilden nedan om du vill ladda ner koden som jag skrivit i denna artikel. Både C# och VB.NET kod finns med. Tips: Om du vill använda klasserna i din programmering välj då att kompilera C# klasserna eftersom de har XML-kommentarer inlagt i koden (går inte att göra i VB.NET). Dessa kommentarer gör att det blir lättare för dig att använda klasserna om du arbetar i en editor med inbyggt stöd för XML-kommentarer, t.ex. Visual Studio .NET.



Resurser

  • Replace-metoden i Regex-klassen

  • RegexOption enum



Lycka till!
Herbjörn
Upp

1 Kommentarer


  1. Mikael Johansson
    14 feb 2006

    Har man pysslat med PHP förut blir man frustrerad att inte detta redan finns i .Net-plattformen. Letade länge i .Net klasser efter funktionaliteten innan jag hittade denna artikel och insåg att det inte fanns någon enkel "standardfunktion"

Skriv en kommentar på artikeln

Ditt betyg på artikeln



Kommentar:





Nyligen

  • 09:09 Vill du köpa medicinska tester?
  • 12:47 Vem beviljar assistansen – kommune
  • 14:17 Någon med erfarenhet av hemstädnin
  • 14:14 Bör man använda sig av en båtförme
  • 14:12 Finns det någon intressant hundblo
  • 14:25 Tips på verktyg för att skapa QR-k
  • 14:23 Tips på verktyg för att skapa QR-k
  • 20:52 Fungerer innskuddsbonuser egentlig

Sidor

  • Hem
  • Bli bonusmedlem
  • Läs artiklar
  • Chatta med andra
  • Sök och erbjud jobb
  • Kontakta oss
  • Studentlicenser
  • Skriv en artikel

Statistik

Antal besökare:
Antal medlemmar:
Antal inlägg:
Online:
På chatten:
4 569 153
27 952
271 704
876
0

Kontakta oss

Frågor runt konsultation, rådgivning, uppdrag, rekrytering, annonsering och övriga ärenden. Ring: 0730-88 22 24 | pelle@pellesoft.se

© 1986-2013 PelleSoft AB. Last Build 4.1.7169.18070 (2019-08-18 10:02:21) 4.0.30319.42000
  • Om
  • Kontakta
  • Regler
  • Cookies