web-dev-qa-db-fra.com

Comment puis-je tronquer une chaîne .NET?

Je voudrais tronquer une chaîne de telle sorte que sa longueur ne soit pas supérieure à une valeur donnée. J'écris dans une table de base de données et je veux m'assurer que les valeurs que j'écris respectent la contrainte du type de données de la colonne.

Par exemple, ce serait bien si je pouvais écrire ce qui suit:

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

Malheureusement, cela déclenche une exception car maxLength dépasse généralement les limites de la chaîne value. Bien sûr, je pourrais écrire une fonction comme celle-ci, mais j’espérais qu’une telle chose existe déjà.

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

Où se trouve l'API insaisissable qui effectue cette tâche? Est-ce qu'il y a un?

340
Steve Guidi

Il n'y a malheureusement pas de méthode Truncate() sur string. Vous devez écrire ce genre de logique vous-même. Ce que vous pouvez faire, cependant, est d’envelopper cette méthode dans une méthode d’extension afin de ne pas la dupliquer partout:

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); 
    }
}

Maintenant nous pouvons écrire:

var someString = "...";
someString = someString.Truncate(2);
521
LBushkin

Ou au lieu de l'opérateur ternaire, vous pouvez utiliser Math.min

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));
    }
}
105
CaffGeek

Je pensais que je mettrais ma mise en œuvre puisque je crois que cela couvre tous les cas qui ont été abordés par les autres et le fait de manière concise et toujours lisible.

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

    return value;
}

Cette solution repose principalement sur de la solution de Ray et ouvre la méthode à utiliser comme méthode d'extension en utilisant le mot clé this, tout comme LBushkin le fait dans sa solution.

35
jpierson

Dans .NET 4.0, vous pouvez utiliser la méthode Take:

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

Non testé pour l'efficacité!

29
Dylan Nicholson

Vous pouvez utiliser LINQ ... cela élimine le besoin de vérifier la longueur de la chaîne. Certes, ce n'est peut-être pas le plus efficace, mais c'est amusant.

string result = string.Join("", value.Take(maxLength)); // .NET 4 Join

ou

string result = new string(value.Take(maxLength).ToArray());
28
tames

Parce que tester les performances est amusant: (en utilisant méthodes d’extension linqpad )

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();

La méthode truncate était "significativement" plus rapide. # microoptimisation

De bonne heure

  • truncate10 5788 ticks écoulés (0,5788 ms) [en répétitions 10K, 5,788E-05 ms par] 
  • smart-trunc10 8206 ticks écoulés (0,8206 ms) [en répétitions 10K, 8,206E-05 ms par] 
  • stringbuilder10 10557 ticks écoulés (1.0557 ms) [en répétition 10K, 0,00010557 ms par] 
  • concat10 45495 ticks écoulés (4,5495 ms) [en répétition 10K, 0,00045495 ms par] 
  • newstring10 72535 ticks écoulés (7,2535 ms) [en répétition 10K, 0,00072535 ms par] 

En retard

  • truncate44 8835 ticks écoulés (0,8835 ms) [en répétitions 10K, 8,835E-05 ms par] 
  • stringbuilder44 13106 ticks écoulés (1,3106 ms) [en répétition 10K, 0,00013106 ms par] 
  • smart-trunc44 14821 ticks écoulés (1,4821 ms) [en répétition 10K, 0,00014821 ms par] 
  • newstring44 144324 ticks écoulés (14,4324 ms) [en répétition 10K, 0,00144324 ms par] 
  • concat44 174610 ticks écoulés (17,461 ms) [en répétition 10K, 0,0017461 ms par] 

Trop long

  • smart-trunc64 6944 ticks écoulés (0,6944 ms) [en répétitions 10K, 6,944E-05 ms par] 
  • truncate64 7686 ticks écoulés (0,7686 ms) [en répétitions 10K, 7,686E-05 ms par] 
  • stringbuilder64 13314 secondes écoulées (1,3314 ms) [en répétition 10K, 0,00013314 ms par] 
  • newstring64 177481 ticks écoulés (17,7481 ms) [en répétition 10K, 0,00177481 ms par] 
  • concat64 241601 ticks écoulés (24,1601 ms) [en répétition 10K, 0,00241601 ms par] 
20
drzaus

Le .NET Framework a une API pour tronquer une chaîne comme ceci:

Microsoft.VisualBasic.Strings.Left(string, int);

Mais dans une application C #, vous préférerez probablement vous débrouiller plutôt que de prendre une dépendance sur Microsoft.VisualBasic.dll, dont la principale raison d'être est la compatibilité ascendante.

11
Joe

On dirait que personne n'a encore posté ceci:

public static class StringExt
{
    public static string Truncate(this string s, int maxLength)
    {
        return s != null && s.Length > maxLength ? s.Substring(0, maxLength) : s;
    }
}

L'utilisation de l'opérateur && le rend légèrement meilleur que la réponse acceptée.

10
Darren

J'ai fait le mien en une ligne un peu comme ça

value = value.Length > 1000 ? value.Substring(0, 1000) : value;
8
SeanKPS

Une variante similaire avec l'opérateur de propagation Null du C # 6

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

Veuillez noter que nous vérifions essentiellement si value est null deux fois ici.

5
Jamie Rees

Prendre @CaffGeek et le simplifier:

public static string Truncate(this string value, int maxLength)
    {
        return string.IsNullOrEmpty(value) ? value : value.Substring(0, Math.Min(value.Length, maxLength));
    }
4
Edwin Beltran

Kndly note que tronquer une chaîne ne signifie pas simplement vouloir couper une chaîne à une longueur spécifiée, mais doit veiller à ne pas diviser le mot. 

par exemple, chaîne: il s'agit d'une chaîne de test. 

Je veux le couper à 11 heures. Si nous utilisons l'une des méthodes données ci-dessus, le résultat sera

c'est un te

Ce n'est pas ce que nous voulons

La méthode que j'utilise n'est peut-être pas aussi parfaite mais elle peut gérer la plupart des situations

public string CutString(string source, int length)
{
        if (source== null || source.Length < length)
        {
            return source;
        }
        int nextSpace = source.LastIndexOf(" ", length);
        return string.Format("{0}...", input.Substring(0, (nextSpace > 0) ? nextSpace : length).Trim());
} 
4
Sen K. Mathew

Toujours pas de méthode Truncate en 2016 pour les chaînes C #. But - Utilisation de la syntaxe C # 6.0:

public static class StringExtension
{
  public static string Truncate(this string s, int max) 
  { 
    return s?.Length > max ? s.Substring(0, max) : s ?? throw new ArgumentNullException(s); 
  }
}

Il fonctionne comme un charme:

"Truncate me".Truncate(8);
Result: "Truncate"
4
Tobias Schiele

Je sais que c'est une vieille question, mais voici une bonne solution:

public static string Truncate(this string text, int maxLength, string suffix = "...")
{
    string str = text;
    if (maxLength > 0)
    {
        int length = maxLength - suffix.Length;
        if (length <= 0)
        {
            return str;
        }
        if ((text != null) && (text.Length > maxLength))
        {
            return (text.Substring(0, length).TrimEnd(new char[0]) + suffix);
        }
    }
    return str;
}

var myString = "hello world"
var myTruncatedString = myString.Truncate(4);

Retours: bonjour ...

4
nologo

Pourquoi pas:

string NormalizeLength(string value, int maxLength)
{
    //check String.IsNullOrEmpty(value) and act on it. 
    return value.PadRight(maxLength).Substring(0, maxLength);
}

c'est-à-dire que l'événement value.Length < maxLength insère des espaces à la fin ou tronque l'excédent.

3
Sri

Juste au cas où il n'y aurait pas assez de réponses ici, voici les miennes :)

public static string Truncate(this string str, 
                              int totalLength, 
                              string truncationIndicator = "")
{
    if (string.IsNullOrEmpty(str) || str.Length < totalLength) 
        return str;

    return str.Substring(0, totalLength - truncationIndicator.Length) 
           + truncationIndicator;
}

utiliser:

"I use it like this".Truncate(5,"~")
3
K. R.

Une autre solution:

return input.Substring(0, Math.Min(input.Length, maxLength));
2
Marek Malczewski

Par souci de (sur) complexité, je vais ajouter ma version surchargée qui remplace les 3 derniers caractères par un Ellipsis en respect du paramètre maxLength.

public static string Truncate(this string value, int maxLength, bool replaceTruncatedCharWithEllipsis = false)
{
    if (replaceTruncatedCharWithEllipsis && maxLength <= 3)
        throw new ArgumentOutOfRangeException("maxLength",
            "maxLength should be greater than three when replacing with an Ellipsis.");

    if (String.IsNullOrWhiteSpace(value)) 
        return String.Empty;

    if (replaceTruncatedCharWithEllipsis &&
        value.Length > maxLength)
    {
        return value.Substring(0, maxLength - 3) + "...";
    }

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

Mes deux cents avec une longueur d'exemple de 30:

  var truncatedInput = string.IsNullOrEmpty(input) ? 
      string.Empty : 
      input.Substring(0, Math.Min(input.Length, 30));
1
Ognyan Dimitrov

Je sais qu'il y a déjà une tonne de réponses, mais mon besoin était de garder le début et la fin de la chaîne intacts, mais de les raccourcir à une longueur inférieure à la longueur maximale.

    public static string TruncateMiddle(string source)
    {
        if (String.IsNullOrWhiteSpace(source) || source.Length < 260) 
            return source;

        return string.Format("{0}...{1}", 
            source.Substring(0, 235),
            source.Substring(source.Length - 20));
    }

Cela permet de créer des URL SharePoint d'une longueur maximale de 260 caractères. 

Je n'ai pas fait de longueur un paramètre car il s'agit d'une constante 260. Je n'ai pas non plus défini la longueur de la première sous-chaîne comme un paramètre, car je souhaite qu'elle soit interrompue à un moment donné. Enfin, la deuxième sous-chaîne est la longueur de la source - 20 depuis que je connais la structure du dossier. 

Cela pourrait facilement être adapté à vos besoins spécifiques.

1
Paul Haan

Je préfère la réponse de jpierson, mais aucun des exemples ici que je peux voir ne gère un paramètre maxLength non valide, comme lorsque maxLength <0.

Les choix seraient soit de gérer l'erreur dans un essai/intercepter, de verrouiller le paramètre maxLength min à 0, ou si maxLength est inférieur à 0, renvoyer une chaîne vide.

Code non optimisé:

public string Truncate(this string value, int maximumLength)
{
    if (string.IsNullOrEmpty(value) == true) { return value; }
    if (maximumLen < 0) { return String.Empty; }
    if (value.Length > maximumLength) { return value.Substring(0, maximumLength); }
    return value;
}
1
deegee

Voici une solution vb.net, indiquez que l’instruction if (bien que laide) améliore les performances, car elle n’a pas besoin de l’instruction substring lorsque la chaîne est déjà inférieure à maxlength ... utiliser...

 <System.Runtime.CompilerServices.Extension()> _
    Public Function Truncate(String__1 As String, maxlength As Integer) As String
        If Not String.IsNullOrEmpty(String__1) AndAlso String__1.Length > maxlength Then
            Return String__1.Substring(0, maxlength)
        Else
            Return String__1
        End If
    End Function
1
Jeroen Bom

Je sais qu'il y a déjà une tonne de réponses ici, mais c'est celle avec laquelle je suis allé, qui gère les deux chaînes nulles et la situation dans laquelle la longueur transmise est négative:

public static string Truncate(this string s, int length)
{
    return string.IsNullOrEmpty(s) || s.Length <= length ? s 
        : length <= 0 ? string.Empty 
        : s.Substring(0, length);
}
1
Ed B

TruncateString

public static string _TruncateString(string input, int charaterlimit)
{
    int characterLimit = charaterlimit;
    string output = input;

    // Check if the string is longer than the allowed amount
    // otherwise do nothing
    if (output.Length > characterLimit && characterLimit > 0)
    {
        // cut the string down to the maximum number of characters
        output = output.Substring(0, characterLimit);
        // Check if the character right after the truncate point was a space
        // if not, we are in the middle of a Word and need to remove the rest of it
        if (input.Substring(output.Length, 1) != " ")
        {
            int LastSpace = output.LastIndexOf(" ");

            // if we found a space then, cut back to that space
            if (LastSpace != -1)
            {
                output = output.Substring(0, LastSpace);
            }
        }
        // Finally, add the "..."
        output += "...";
    }
    return output;
}
0
Sud

En plus des possibilités évoquées ci-dessus, j'aimerais partager ma solution . C'est une méthode d'extension qui autorise null (renvoie string.Empty). Il existe également un deuxième fichier .Truncate () permettant de l'utiliser avec un Ellipsis. Attention, les performances ne sont pas optimisées.

public static string Truncate(this string value, int maxLength) =>
    (value ?? string.Empty).Substring(0, (value?.Length ?? 0) <= (maxLength < 0 ? 0 : maxLength) ? (value?.Length ?? 0) : (maxLength < 0 ? 0 : maxLength));
public static string Truncate(this string value, int maxLength, string Ellipsis) =>
    string.Concat(value.Truncate(maxLength - (((value?.Length ?? 0) > maxLength ? Ellipsis : null)?.Length ?? 0)), ((value?.Length ?? 0) > maxLength ? Ellipsis : null)).Truncate(maxLength);
0
Raymond Osterbrink