Suche…


Bemerkungen

In .NET-Zeichenfolgen ist System.String eine Folge von Zeichen System.Char . Jedes Zeichen ist eine UTF-16-codierte System.String . Diese Unterscheidung ist wichtig, da die Definition der Zeichen in gesprochener Sprache und die Definition von Zeichen in .NET (und vielen anderen Sprachen) unterschiedlich sind.

Ein Zeichen , das korrekt als Graphem bezeichnet werden sollte , wird als Glyphe angezeigt und durch einen oder mehrere Unicode- Codepunkte definiert. Jeder Codepunkt wird dann in einer Folge von Codeeinheiten codiert. Jetzt sollte klar sein, warum ein einzelnes System.Char nicht immer ein Graphem darstellt. Sehen wir uns in der Realität an, wie sie sich unterscheiden:

  • Ein Graphem kann aufgrund der Kombination von Zeichen zu zwei oder mehr Codepunkten führen: à setzt sich aus zwei Codepunkten zusammen: U + 0061 LATEINER KLEINER BUCHSTABE A und U + 0300 . Dies ist der häufigste Fehler, weil "à".Length == 2 während Sie 1 erwarten können.
  • Es gibt Zeichen dupliziert, zum Beispiel à eine einzige Codepunkt U + 00E0 Kleines a mit Gravis oder zwei Code-Punkte sein können , wie oben erläutert. Offensichtlich müssen sie dasselbe vergleichen: "\u00e0" == "\u0061\u0300" (auch wenn "\u00e0".Length != "\u0061\u0300".Length ). Dies ist möglich, da die Zeichenfolge normalisiert wird , indem die Methode String.Normalize() verwendet wird.
  • Eine Unicode - Sequenz , die eine zusammengesetzte oder zerlegt Sequenz enthalten kann, beispielsweise Zeichen U + D55C HAN CHARACTER kann einen einzigen Codepunkt (codiert als einzelne Code-Einheit in UTF-16) oder eine zerlegt Sequenz seiner Silben ᄒ, und . Sie müssen gleich verglichen werden.
  • Ein Codepunkt kann in mehr als eine Codeeinheit codiert werden: Das Zeichen 𠂊 U + 2008A HAN CHARACTER ist als zwei System.Char Codierung ( "\ud840\udc8a" ) "\ud840\udc8a" auch wenn es sich nur um einen Codepunkt handelt: UTF-16 Kodierung hat keine feste Größe! Dies ist eine Quelle unzähliger Fehler (auch schwerwiegender Sicherheitsfehler). Wenn Ihre Anwendung beispielsweise eine maximale Länge anwendet und den String blind verkürzt, können Sie einen ungültigen String erstellen.
  • Einige Sprachen haben digraph und trigraphs, zum Beispiel in der Tschechischen ch ist ein Standalone - Brief (nach h und bevor ich dann , wenn eine Liste von Strings Bestellung Sie fyzika vor Chemie hat.

Es gibt viel mehr Probleme bei der Textverarbeitung, siehe beispielsweise Wie kann ich einen Unicode-fähigen Zeichenvergleich durchführen? für eine breitere Einführung und mehr Links zu verwandten Argumenten.

Im Allgemeinen können Sie beim Umgang mit internationalem Text diese einfache Funktion verwenden, um Textelemente in einer Zeichenfolge aufzulisten (um Unicode-Ersatzzeichen und die Kodierung nicht zu beschädigen):

public static class StringExtensions
{
    public static IEnumerable<string> EnumerateCharacters(this string s)
    {
        if (s == null)
            return Enumerable.Empty<string>();

        var enumerator = StringInfo.GetTextElementEnumerator(s.Normalize());
        while (enumerator.MoveNext())
            yield return (string)enumerator.Value;
    }
}

Zähle verschiedene Charaktere

Wenn Sie unterschiedliche Zeichen zählen müssen, können Sie aus den im Abschnitt " Bemerkungen" erläuterten Gründen nicht einfach die Length -Eigenschaft verwenden, da es sich bei der Länge des Arrays von System.Char nicht um Zeichen, sondern um Codeeinheiten (nicht Unicode-Codepunkte) handelt noch Grapheme). Wenn Sie beispielsweise einfach text.Distinct().Count() schreiben text.Distinct().Count() Sie falsche Ergebnisse, richtigen Code:

int distinctCharactersCount = text.EnumerateCharacters().Count();

Ein weiterer Schritt besteht darin, das Vorkommen jedes Zeichens zu zählen. Wenn die Leistung kein Problem darstellt, können Sie dies einfach wie folgt tun (in diesem Beispiel unabhängig von Fall):

var frequencies = text.EnumerateCharacters()
    .GroupBy(x => x, StringComparer.CurrentCultureIgnoreCase)
    .Select(x => new { Character = x.Key, Count = x.Count() };

Zeichen zählen

Wenn Sie Zeichen zählen müssen, können Sie aus den im Abschnitt " Bemerkungen" erläuterten Gründen nicht einfach die Length -Eigenschaft verwenden, da es sich bei der Länge des Arrays von System.Char nicht um Zeichen, sondern um Codeeinheiten (nicht um Unicode-Codepunkte) handelt Graphemen). Korrekter Code lautet dann:

int length = text.EnumerateCharacters().Count();

Eine kleine Optimierung kann die EnumerateCharacters() Erweiterungsmethode speziell für diesen Zweck neu schreiben:

public static class StringExtensions
{
    public static int CountCharacters(this string text)
    {
        if (String.IsNullOrEmpty(text))
            return 0;

        int count = 0;
        var enumerator = StringInfo.GetTextElementEnumerator(text);
        while (enumerator.MoveNext())
            ++count;

        return count;
    }
}

Zählen Sie Vorkommen eines Zeichens

Aus den im Abschnitt " Anmerkungen" genannten Gründen können Sie dies nicht einfach tun (es sei denn, Sie möchten das Vorkommen einer bestimmten Code-Einheit zählen):

int count = text.Count(x => x == ch);

Sie benötigen eine komplexere Funktion:

public static int CountOccurrencesOf(this string text, string character)
{
    return text.EnumerateCharacters()
        .Count(x => String.Equals(x, character, StringComparer.CurrentCulture));
}

Beachten Sie, dass der Zeichenkettenvergleich (im Gegensatz zum Zeichenvergleich, der kulturinvariant ist) immer nach Regeln für eine bestimmte Kultur durchgeführt werden muss.

String in Blöcke mit fester Länge aufteilen

Wir können nicht einen String in beliebigen Punkten brechen (weil ein System.Char nicht allein gültig sein kann , weil es sich um eine Kombination von Zeichen oder ein Teil eines Surrogat ist) , dann Code, berücksichtigen müssen (beachten Sie, dass mit der Länge meine ich die Anzahl der Grapheme nicht die Anzahl Code-Einheiten ):

public static IEnumerable<string> Split(this string value, int desiredLength)
{
    var characters = StringInfo.GetTextElementEnumerator(value);
    while (characters.MoveNext())
        yield return String.Concat(Take(characters, desiredLength));
}

private static IEnumerable<string> Take(TextElementEnumerator enumerator, int count)
{
    for (int i = 0; i < count; ++i)
    {
        yield return (string)enumerator.Current;

        if (!enumerator.MoveNext())
            yield break;
    }
}

Konvertieren Sie die Zeichenfolge in eine andere Kodierung

.NET-Zeichenfolgen enthalten System.Char (UTF-16-Codeeinheiten). Wenn Sie Text mit einer anderen Kodierung speichern (oder verwalten) möchten, müssen Sie mit einem Array von System.Byte .

Konvertierungen werden von Klassen durchgeführt, die von System.Text.Encoder und System.Text.Decoder abgeleitet System.Text.Encoder und zusammen in eine andere Codierung konvertieren können (von einem Byte X- codierten Array byte[] in einen UTF-16-codierten System.String und einen Vice) -versa).

Da der Encoder / Decoder normalerweise sehr nahe beieinander arbeitet, werden sie in einer von System.Text.Encoding abgeleiteten Klasse zusammengefasst. System.Text.Encoding bieten abgeleitete Klassen Konvertierungen zu / von gängigen Codierungen (UTF-8, UTF-16 usw.).

Beispiele:

Konvertieren Sie eine Zeichenfolge in UTF-8

byte[] data = Encoding.UTF8.GetBytes("This is my text");

Konvertieren Sie UTF-8-Daten in einen String

var text = Encoding.UTF8.GetString(data);

Kodierung einer vorhandenen Textdatei ändern

Dieser Code liest den Inhalt einer UTF-8-codierten Textdatei und speichert sie als UTF-16 codiert ab. Beachten Sie, dass dieser Code nicht optimal ist, wenn die Datei groß ist, da der gesamte Inhalt in den Speicher gelesen wird:

var content = File.ReadAllText(path, Encoding.UTF8);
File.WriteAllText(content, Encoding.UTF16);

Virtuelle Object.ToString () - Methode

Alles in .NET ist ein Objekt, daher hat jeder Typ die ToString() Methode, die in der Object Klasse definiert ist, die überschrieben werden kann. Die Standardimplementierung dieser Methode gibt nur den Namen des Typs zurück:

public class Foo
{
}

var foo = new Foo();
Console.WriteLine(foo); // outputs Foo

ToString() wird implizit aufgerufen, wenn der Wert mit einer Zeichenfolge verknüpft wird:

public class Foo
{
    public override string ToString()
    {
        return "I am Foo";
    }
}

var foo = new Foo();
Console.WriteLine("I am bar and "+foo);// outputs I am bar and I am Foo

Das Ergebnis dieser Methode wird auch von Debugging-Tools ausgiebig verwendet. Wenn Sie diese Methode aus irgendeinem Grund nicht überschreiben möchten, sondern anpassen möchten, wie der Debugger den Wert Ihres Typs anzeigt, verwenden Sie das DebuggerDisplay-Attribut ( MSDN ):

// [DebuggerDisplay("Person = FN {FirstName}, LN {LastName}")]
[DebuggerDisplay("Person = FN {"+nameof(Person.FirstName)+"}, LN {"+nameof(Person.LastName)+"}")]
public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set;}
    // ...
}

Unveränderlichkeit von Saiten

Strings sind unveränderlich. Sie können die vorhandene Zeichenfolge einfach nicht ändern. Bei jeder Operation der Zeichenfolge wird eine neue Instanz der Zeichenfolge mit einem neuen Wert erstellt. Das bedeutet, wenn Sie ein einzelnes Zeichen in einer sehr langen Zeichenfolge ersetzen müssen, wird Speicher für einen neuen Wert reserviert.

string veryLongString = ...
// memory is allocated
string newString = veryLongString.Remove(0,1); // removes first character of the string.

Wenn Sie viele Operationen mit einem String-Wert durchführen müssen, verwenden Sie die StringBuilder Klasse, die für eine effiziente Bearbeitung von Strings ausgelegt ist:

var sb = new StringBuilder(someInitialString);
foreach(var str in manyManyStrings)
{
    sb.Append(str);
} 
var finalString = sb.ToString();

Vergleichende Zeichenketten

Trotz String ist ein Referenztyp == Operator vergleicht Zeichenfolgenwerte statt Referenzen.

Wie Sie vielleicht wissen, ist string nur ein Array von Zeichen. Wenn Sie jedoch der Meinung sind, dass die Gleichheitsprüfung und der Vergleich von Zeichenfolgen Zeichen für Zeichen vorgenommen werden, sind Sie falsch. Diese Operation ist kulturspezifisch (siehe Anmerkungen unten): Einige Zeichenfolgen können je nach Kultur als gleich behandelt werden.

Denken Sie zweimal nach, bevor Sie die Gleichheitsprüfung kurzschließen, indem Sie die Length Eigenschaften von zwei Strings vergleichen!

Verwenden Sie Überladungen der String.Equals Methode, die zusätzlichen StringComparison Enumerationswert akzeptieren, wenn Sie das Standardverhalten ändern müssen.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow