Gå til innhold

endre en karakter i en streng


Anbefalte innlegg

Heisan

I Clarion kan jeg gjøre slik:

MyString = 'Hello World'
MyString[2] = 'a'
Message(MyString)

Resultatet vil gi "Hallo World"

 

Prøvde dette i VB men får beskjed at "Property CHARS is ReadOnly"

 

Vet jeg kan gjøre det slik:

MyString = mid(MyString,1,1) & "a" & mid(MyString,3,len(MyString)-3)

men hallo.... må da være en enklere måte å gjøre det på... eller...

 

Ole

Lenke til kommentar
Videoannonse
Annonse

I .NET, i motsetning til VB6, er strenger immutable - dvs. uforanderlige, hovedsaklig for å øke ytelsen til programmet. Kompilatoren kan dermed la flere streng-variabler peke til samme område uten at det er fare for at det kan skape konflikt dersom noen av disse strengene blir forsøkt å bli endret. Det er derfor ikke mulig å endre en streng i .NET etter den har blitt skapt.

 

Dersom du føler det er behov for å lage/endre en streng i flere omganger, vil jeg anbefale at du bruker System.Text.StringBuilder-klassen:

Dim oText As New System.Text.StringBuilder("Dtartstreng. ")

 

' Legger til tekst i enden av strengen

oText.Append("Hallo ")

oText.Append("verdn. ")

 

' * Modifikasjoner *

oText = oText.Replace("verdn", "verden")

oText.Chars(0) = "S"

oText.Insert(0, "TTEST: ")

 

' Legger til 42 kopier av 'a'

oText.Append("a", 42)

oText.Append(". ")

 

' Legger til en ny linje

oText.AppendLine("Ny linje kommer!")

oText.AppendFormat("Denne {0} gjør det {1} å sette inn verdier i en streng.", _

"metoden", "enkelt")

 

' Fjerner en karakter

oText.Remove(0, 1)

 

' Viser resultatet

MessageBox.Show(oText.ToString)

Endret av aadnk
Lenke til kommentar
> men hallo.... må da være en enklere måte å gjøre det på... eller...

VB må da ha Left() og Right()? Det er enklere enn Mid()...

8139087[/snapback]

Ytelsen blir ikke forbedret av den grunn - å bygge opp en ny streng ved å dele den opp i to deler og sette den sammen er ikke akkurat en optimal operasjon. Dessuten, rent kodemessig sparer en med Left() og Right() kun et par tastetrykk - nei, StringBuilder er nok å foretrekke.

 

For øvrig, dersom det er VB6 du tenker på, kan en faktisk gjøre dette direkte med MID()-nøkkelordet:

    Dim sTest As String

   

    sTest = "Hello world"

    Mid(sTest, 2, 1) = "a"

   

    MsgBox sTest

Endret av aadnk
Lenke til kommentar
Ytelsen blir ikke forbedret av den grunn - å bygge opp en ny streng ved å dele den opp i to deler og sette den sammen er ikke akkurat en optimal operasjon. Dessuten, rent kodemessig sparer en med Left() og Right() kun et par tastetrykk - nei, StringBuilder er nok å foretrekke.

8139405[/snapback]

 

Feil. Det er overkill å bruke stringbuilder på så enkle ting. Det vil faktisk gå treigere siden det krever litt ressurser å initialisere stringbuilder objektet. Om man skal f.eks. slå sammen mange string'er så vil stringbuilder være å foretrekke.

 

MinString = MinString.SubString(0,5) & 'A' & MinString.SubString(6)

Er rette måten å gjøre dette på i VB.Net.

 

En liten hemmelighet er at i .Net er ikke strings imutable egentlig ;) "MinString[6] = 'A'"-type kode kan man enkelt gjøre med unsafe kode i C#, men ikke i VB.Net. Uansett så gidder man som regel ikke dette om man ikke har spesielle behov for ytelse.

Endret av jorn79
Lenke til kommentar
> men hallo.... må da være en enklere måte å gjøre det på... eller...

VB må da ha Left() og Right()? Det er enklere enn Mid()...

8139087[/snapback]

Spiller ingen rolle om man bruker right, left elle rmid for mitt vedkommende. Jeg vil endre en karakter i en streng og thats it. Skal se på string builder klassen. Tror kansje den har det jeg trenger

 

Når det gjelder ytelse så spiller det ingen rolle i dette tilfellet da denn ekoden kunn skal kjøres en gang ved oppstart. Greia er at jeg skal endre karakterer i en lang streng på bakgrunn av et binær mønster og da blir kode med left, right eller mid rimelig ulesbart. Derimot kjøper jeg glatt den mid(ThisString,5,1) = "A" hvis det fungerer i VB.NET2005 da. Det vil jo vise seg :-D

 

Ole

Lenke til kommentar
Kanskje du kan bruke en char array?

8140802[/snapback]

 

Da må du først kopiere string'en over i en char array. Endre på en av char'ene og så kopiere alt til en ny string. Tungvindt... Tror også det vil være treigere enn .SubString eksempelet over. .SubString bruker faktisk unsafe kode :)

 

Dim s as String = "tester"
Dim c() as Char = s.ToCharArray()
c(2) = 'Z'
s = new string(c)

 

 

 

Ex. på unsafe C# kode for å endre på en bokstav:

unsafe private void Test()
{
   string s = "tester";
   fixed (char* sptr = s)
       sptr[2] = 'Z';
}

Lenke til kommentar
Kanskje du kan bruke en char array?

8140802[/snapback]

 

Da må du først kopiere string'en over i en char array. Endre på en av char'ene og så kopiere alt til en ny string. Tungvindt... Tror også det vil være treigere enn .SubString eksempelet over. .SubString bruker faktisk unsafe kode :)

 

Dim s as String = "tester"
Dim c() as Char = s.ToCharArray()
c(2) = 'Z'
s = new string(c)

 

 

 

Ex. på unsafe C# kode for å endre på en bokstav:

unsafe private void Test()
{
   string s = "tester";
   fixed (char* sptr = s)
       sptr[2] = 'Z';
}

8140924[/snapback]

 

Haha. Den var god.

 

Ole

Lenke til kommentar
Feil. Det er overkill å bruke stringbuilder på så enkle ting. Det vil faktisk gå treigere siden det krever litt ressurser å initialisere stringbuilder objektet. Om man skal f.eks. slå sammen mange string'er så vil stringbuilder være å foretrekke.

8140452[/snapback]

Det trodde opprinnelig jeg også, men etter å ha undersøkt saken inngående gjennom testing og eksperimentering fant jeg ut at StringBuilder faktisk er mer effektiv enn Mid() og Substring() - og, overraskende nok, gjorde sistnevnte metode det verst i testen:

* Starting string test.
State the amount of desired reruns: 500000

StringBuilder:
   Total time:     205 ms (391407233 ticks)
   Average time:   0,00041 ms (782,814466 ticks)

Substring:
   Total time:     242 ms (461467517 ticks)
   Average time:   0,000484 ms (922,935034 ticks)

Mid:
   Total time:     228 ms (434866320 ticks)
   Average time:   0,000456 ms (869,73264 ticks)

 

Kildekoden for testapplikasjonen (husk å kjøre den kompilerte applikasjonen om du ønsker å teste det), finner du her:

Klikk for å se/fjerne innholdet nedenfor
Imports System.Text

 

Module modTest

 

    Sub Main()

 

        Dim Reruns As Integer

 

        ' Initiating the test

        Console.WriteLine("Starting string test.")

 

        ' Get the amount of times to run the test

        Integer.TryParse(Query("State the amount of desired reruns"), Reruns)

 

        Do

            ' Execute the test

            Console.WriteLine() ' New line

            StringTest(Reruns)

 

            ' Continue doing the test until the user refuse to restart

        Loop Until Query("Do you want to restart? (Y, N)").ToUpper <> "Y"

 

    End Sub

 

    Public Sub StringTest(ByVal Reruns As Integer)

 

        Dim oWatches() As Stopwatch = {New Stopwatch, New Stopwatch, New Stopwatch}

        Dim sText As String = "Hello world.", sOutput As String, oStringBuilder As StringBuilder

 

        For Tell = 0 To Reruns

 

            ' Test string builder

            oWatches(0).Start()

            oStringBuilder = New StringBuilder(sText, sText.Length)

            oStringBuilder.Chars(1) = "a"

            sOutput = oStringBuilder.ToString

            oWatches(0).Stop()

 

            ' Test conventional method

            oWatches(1).Start()

            sOutput = Mid(sText, 1, 1) & "a" & Mid(sText, 3)

            oWatches(1).Stop()

 

            ' Test .NET-method

            oWatches(2).Start()

            sOutput = sText.Substring(0, 1) & "a" & sText.Substring(2)

            oWatches(2).Stop()

 

        Next

 

        ' Write the results

        WriteStatistics(oWatches(0), Reruns, "StringBuilder")

        WriteStatistics(oWatches(1), Reruns, "Substring")

        WriteStatistics(oWatches(2), Reruns, "Mid")

 

    End Sub

 

    Public Sub WriteStatistics(ByVal Watch As Stopwatch, ByVal Reruns As Integer, ByVal Name As String)

 

        ' Write the results

        Console.WriteLine(Name & ":")

        Console.WriteLine(MaxLenght("    Total time:", 20) & Watch.ElapsedMilliseconds & _

        " ms (" & Watch.ElapsedTicks & " ticks)")

        Console.WriteLine(MaxLenght("    Average time:", 20) & Watch.ElapsedMilliseconds / Reruns & _

        " ms (" & Watch.ElapsedTicks / Reruns & " ticks)")

        Console.WriteLine()

 

    End Sub

 

    Public Function Query(ByVal Question As String) As String

 

        ' Ask the user

        Console.Write(Question & ": ")

 

        ' Return the given answer

        Return Console.ReadLine

 

    End Function

 

    Public Function MaxLenght(ByVal Text As String, ByVal TotalSize As Integer) As String

 

        ' See if we need to remove or append to the string

        If TotalSize < Text.Length Then

            ' Returns only a portion of the original string

            Return Text.Substring(0, TotalSize)

        Else

            ' Returns the string filled to its upper limit

            Return Text & New String(" ", TotalSize - Text.Length)

        End If

 

    End Function

 

End Module

Lenke til kommentar
Regnet ikke med at folk ville tro på at strings ikke er imutable, så jeg måtte jo ha et lite bevis  :cool:

8140962[/snapback]

I følge Wikipedia har ikke dette noe relevans for hvorvidt objektet er å regne for å være immutable eller ikke:

Immutability does not imply that the object as stored in the computer's memory is unwriteable. Rather, immutability is a compile-time construct that indicates what a programmer should do, not necessarily what he can do (for instance, by circumventing the type system or violating const correctness in C or C++).
Endret av aadnk
Lenke til kommentar
Det trodde opprinnelig jeg også, men etter å ha undersøkt saken inngående gjennom testing og eksperimentering fant jeg ut at StringBuilder faktisk er mer effektiv enn Mid() og Substring() - og, overraskende nok, gjorde sistnevnte metode det verst i testen

8142025[/snapback]

 

Du hadde rett :)

 

string klassen inneholder faktisk funksjonalitet for å gjøre dette.

internal unsafe void SetChar(int index, char value)
{
   if (index >= this.Length)
   {
       throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_Index"));
   }
   fixed (char* chRef = &this.m_firstChar)
   {
       chRef[index] = value;
   }
}

Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
×
×
  • Opprett ny...