535 Stimmen

Wie kann ich eine .NET-Zeichenkette abschneiden?

Ich möchte eine Zeichenkette so abschneiden, dass sie nicht länger als ein bestimmter Wert ist. Ich schreibe in eine Datenbanktabelle und möchte sicherstellen, dass die Werte, die ich schreibe, die Einschränkung des Datentyps der Spalte erfüllen.

Es wäre zum Beispiel schön, wenn ich Folgendes schreiben könnte:

string NormalizeLength(string value, int maxLength)
{
    return value.Substring(0, maxLength);
}

Leider führt dies zu einer Ausnahme, da maxLength im Allgemeinen die Grenzen der Zeichenfolge überschreitet value . Natürlich könnte ich eine Funktion wie die folgende schreiben, aber ich hatte gehofft, dass so etwas bereits existiert.

string NormalizeLength(string value, int maxLength)
{
    return value.Length <= maxLength ? value : value.Substring(0, maxLength);
} 

Wo ist die schwer fassbare API, die diese Aufgabe erfüllt? Gibt es eine?

31 Stimmen

Für das Protokoll, Strings sind unveränderlich Sie können nicht truncate Sie können nur eine abgeschnittene Kopie von ihnen zurück. Ich weiß, das ist pingelig.

3 Stimmen

@John Weldon: Das ist wahrscheinlich der Grund, warum die Memberfunktion nicht existiert - sie folgt nicht der Semantik des Datentyps. Eine kleine Anmerkung am Rande, StringBuilder können Sie durch Verkürzung der Länge abschneiden, aber Sie müssen immer noch die Längenprüfung durchführen, um eine Verbreiterung der Zeichenkette zu vermeiden.

1 Stimmen

Unabhängig davon, für welche Lösung Sie sich entscheiden, sollten Sie vor dem Aufruf von Substring oder dem Zugriff auf die Length-Eigenschaft eine Prüfung auf eine Null-Zeichenkette hinzufügen.

829voto

LBushkin Punkte 124894

Es gibt keine Truncate() Methode auf String, leider. Diese Art von Logik müssen Sie selbst schreiben. Was Sie jedoch tun können, ist, dies in eine Erweiterungsmethode zu verpacken, damit Sie es nicht überall duplizieren müssen:

public static class StringExt
{
    public static string Truncate(this string value, int maxLength)
    {
        if (string.IsNullOrEmpty(value)) return value;
        return value.Length <= maxLength ? value : value.Substring(0, maxLength); 
    }
}

Jetzt können wir schreiben:

var someString = "...";
someString = someString.Truncate(2);
2021-09-17 Alternative mit Suffix und c#8 nullable reference types.
public static class StringExt
{
    public static string? Truncate(this string? value, int maxLength, string truncationSuffix = "…")
    {
        return value?.Length > maxLength
            ? value.Substring(0, maxLength) + truncationSuffix
            : value;
    }
}

Zum Schreiben:

"abc".Truncate(2);          // "ab…"
"abc".Truncate(3);          // "abc"
((string)null).Truncate(3); // null

8 Stimmen

Große Lösung, aber daran erinnert, dass dies nur in NET 3.5 und Up funktioniert. Versuchen Sie es nicht in NET2.0.

8 Stimmen

Solange Sie in VS 2008 und vermutlich VS 2010 sind, können Sie dies tun, auch wenn Sie auf .Net 2.0 abzielen. danielmoth.com/Blog/

4 Stimmen

Dies wird fehlschlagen, wenn maxLength ist ein negativer Wert.

176voto

CaffGeek Punkte 21343

Anstelle des ternären Operators könnten Sie auch Math.min verwenden

public static class StringExt
{
    public static string Truncate( this string value, int maxLength )
    {
        if (string.IsNullOrEmpty(value)) { return value; }

        return value.Substring(0, Math.Min(value.Length, maxLength));
    }
}

11 Stimmen

Raffiniert! Und der folgende Ausdruck ist so optimiert, dass er einen Verweis auf die ursprüngliche Zeichenfolge zurückgibt: value.Substring(0, value.Length) .

5 Stimmen

Leider ist es nicht für Fälle optimiert, in denen value.Length kleiner als MaxLength ist, was bei einigen Daten häufig vorkommt. Auch die Length-Eigenschaft von String sollte großgeschrieben werden.

1 Stimmen

Dies wird fehlschlagen, wenn maxLength ein negativer Wert ist.

55voto

drzaus Punkte 22843

Weil Leistungstests Spaß machen: (mit linqpad Erweiterungsmethoden )

var val = string.Concat(Enumerable.Range(0, 50).Select(i => i % 10));

foreach(var limit in new[] { 10, 25, 44, 64 })
    new Perf<string> {
        { "newstring" + limit, n => new string(val.Take(limit).ToArray()) },
        { "concat" + limit, n => string.Concat(val.Take(limit)) },
        { "truncate" + limit, n => val.Substring(0, Math.Min(val.Length, limit)) },
        { "smart-trunc" + limit, n => val.Length <= limit ? val : val.Substring(0, limit) },
        { "stringbuilder" + limit, n => new StringBuilder(val, 0, Math.Min(val.Length, limit), limit).ToString() },
    }.Vs();

El truncate Methode war "deutlich" schneller. #microoptimization

Frühzeitig

  • truncate10 5788 verstrichene Ticks (0,5788 ms) [in 10K Wiederholungen, 5,788E-05 ms pro]
  • smart-trunc10 8206 Ticks verstrichen (0,8206 ms) [in 10K Wiederholungen, 8,206E-05 ms pro]
  • stringbuilder10 10557 Ticks verstrichen (1,0557 ms) [in 10K Wiederholungen, 0,00010557 ms pro]
  • concat10 45495 Ticks verstrichen (4,5495 ms) [in 10K Wiederholungen, 0,00045495 ms pro]
  • newstring10 72535 Ticks verstrichen (7,2535 ms) [in 10K Wiederholungen, 0,00072535 ms pro]

Späte

  • truncate44 8835 Ticks verstrichen (0,8835 ms) [in 10K Wiederholungen, 8,835E-05 ms pro]
  • stringbuilder44 13106 Ticks verstrichen (1,3106 ms) [in 10K Wiederholungen, 0,00013106 ms pro]
  • smart-trunc44 14821 Ticks verstrichen (1,4821 ms) [in 10K Wiederholungen, 0,00014821 ms pro]
  • newstring44 144324 Ticks verstrichen (14,4324 ms) [in 10K Wiederholungen, 0,00144324 ms pro]
  • concat44 174610 Ticks verstrichen (17,461 ms) [in 10K Wiederholungen, 0,0017461 ms pro]

Zu lang

  • smart-trunc64 6944 Ticks verstrichen (0,6944 ms) [in 10K Wiederholungen, 6,944E-05 ms pro]
  • truncate64 7686 Ticks verstrichen (0,7686 ms) [in 10K Wiederholungen, 7,686E-05 ms pro]
  • stringbuilder64 13314 Ticks verstrichen (1,3314 ms) [in 10K Wiederholungen, 0,00013314 ms pro]
  • newstring64 177481 Ticks verstrichen (17,7481 ms) [in 10K Wiederholungen, 0,00177481 ms pro]
  • concat64 241601 Ticks verstrichen (24,1601 ms) [in 10K Wiederholungen, 0,00241601 ms pro]

0 Stimmen

Vielen Dank für die vielen nützlichen Benchmarks! ... und Linkpad rockt!

0 Stimmen

Hmm, ich bin mit dieser Bank nicht einverstanden. 1) Die Eingabezeichenfolge val ist eine Konstante. 2) Die Abschneidelänge limit ist für alle 10k Iterationen konstant. 3) Es scheint, dass die Ausgabe sofort verworfen wird. All diese Faktoren können dazu führen, dass der Compiler Dinge wegoptimiert. Ich habe meine eigenen Tests durchgeführt und festgestellt, dass das, was Sie "smart-trunc" nennen, im Durchschnitt deutlich (20 %) schneller ist als "truncate", und das bei 10 Mio. Iterationen im Release-/Produktionsmodus (ich habe auch einen signifikanten Unterschied zwischen dem Debug-Modus und dem Release-Modus festgestellt).

0 Stimmen

@JHBonarius ich dachte, dass der YMMV Vorbehalt für Leistungstests etwas offensichtlich sein sollte und ich wollte nur den Ball ins Rollen bringen ;) und selbst wenn Sie absolut Recht haben, vergessen Sie nicht, dass wir über Unterschiede von weniger als einem Tausendstel einer Millisekunde sprechen...

50voto

jpierson Punkte 14912

Ich dachte, ich würde meine Implementierung einbringen, da ich glaube, dass sie alle Fälle abdeckt, die von den anderen angesprochen wurden, und zwar auf eine prägnante Art und Weise, die noch lesbar ist.

public static string Truncate(this string value, int maxLength)
{
    if (!string.IsNullOrEmpty(value) && value.Length > maxLength)
    {
        return value.Substring(0, maxLength);
    }

    return value;
}

Diese Lösung stützt sich hauptsächlich auf die Rays Lösung und öffnet die Methode für die Verwendung als Erweiterungsmethode, indem sie die este Schlüsselwort ebenso wie LBushkin tut in seiner Lösung.

0 Stimmen

Dies wird fehlschlagen, wenn maxLength ein negativer Wert ist.

16 Stimmen

@Bernard - Ich würde empfehlen, keinen negativen Wert für das Argument maxLength zu übergeben, da dies ein unerwarteter Wert ist. Die Substring-Methode verfolgt denselben Ansatz, so dass es keinen Grund gibt, die von ihr ausgelöste Ausnahme zu verbessern.

0 Stimmen

Ich glaube nicht, dass die IsNullOrEmpty-Prüfung notwendig ist? (1) Wenn value null ist, sollte es keine Möglichkeit geben, diese Erweiterungsmethode aufzurufen. (2) Wenn value eine leere Zeichenkette ist, schlägt die Prüfung von value.Length > maxLength fehl.

49voto

Dylan Nicholson Punkte 1155

In .NET 4.0 können Sie die Take Methode:

string.Concat(myString.Take(maxLength));

Nicht auf Effizienz geprüft!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X