web-dev-qa-db-fra.com

Couper la chaîne à partir de la fin d'une chaîne dans .NET - pourquoi manque-t-il?

J'ai constamment besoin de cela et je suis constamment frustré par le fait que les fonctions Trim (), TrimStart () et TrimEnd () ne prennent pas de chaînes en tant qu'entrées. Vous appelez EndsWith () sur une chaîne et découvrez si elle se termine par une autre chaîne, mais si vous souhaitez la supprimer de la fin, vous devez effectuer des hacks de sous-chaîne pour le faire (ou appeler Remove () et priez pour qu'il soit le seul cas ...)

Pourquoi cette fonction de base manque-t-elle dans .NET? Et deuxièmement, toute recommandation pour un moyen simple de mettre en œuvre ceci (de préférence pas la voie de l'expression régulière ...)

48
Brady Moritz

TrimEnd() (et les autres méthodes de rognage) acceptent les caractères à rogner, mais pas les chaînes. Si vous voulez vraiment une version capable de couper des chaînes entières, vous pouvez créer une méthode d'extension. Par exemple...

public static string TrimEnd(this string input, string suffixToRemove,
    StringComparison comparisonType) {

    if (input != null && suffixToRemove != null
      && input.EndsWith(suffixToRemove, comparisonType)) {
        return input.Substring(0, input.Length - suffixToRemove.Length);
    }
    else return input;
}

Ceci peut alors être appelé comme les méthodes intégrées.

49
Daniel Renshaw

EDIT - intégré dans une méthode d’extension pratique:

public static string TrimEnd(this string source, string value)
{
    if (!source.EndsWith(value))
        return source;

    return source.Remove(source.LastIndexOf(value));
}

donc vous pouvez juste faire s = s.TrimEnd("DEF");

63
Yahia

Utiliser le code de Daniel et l’envelopper dans un moment plutôt que dans une if droite donne une fonctionnalité plus proche de la fonction Microsoft Trim:

public static string TrimEnd(this string input, string suffixToRemove)
{
    while (input != null && suffixToRemove != null && input.EndsWith(suffixToRemove))
    {
        input = input.Substring(0, input.Length - suffixToRemove.Length);
    }
    return input;
}
7
Ryan Amies

J'ai bousillé cette méthode d'extension rapide.

Pas positif, ça marche (je ne peux pas le tester pour le moment), mais la théorie est bonne.

    public static string RemoveLast(this string source, string value)
    {
        int index = source.LastIndexOf(value);
        return index != -1 ? source.Remove(index, value.Length) : source;
    }
6
Alastair Pitts

Regex remplacer peut être votre ami dans ce cas.

var str = "Hello World!";
str = Regex.Replace(str, @"World!$", "");
//str == "Hello"
3
zellio

J'aime que mon TrimEnd supprime toutes les occurrences de la chaîne à la fin et pas seulement la dernière.

public static string TrimEnd(this string str, string trimStr)
{
    if (string.IsNullOrEmpty(str) || string.IsNullOrEmpty(trimStr)) return str;

    while(str.EndsWith(trimStr))
    {
        str = str.Remove(str.LastIndexOf(trimStr));
    }
    return str;
}
2
LUKE

C'est ce que vous vous opposez à devoir faire?

if (theString.endsWith(theOtherString))
{
   theString = theString.Substring(0, theString.Length - theOtherString.Length);
}
1
Ben M
.TrimStart("AB".ToCharArray())
0
Justin

Trim (), TrimStart () et TrimEnd () sont des méthodes qui remplacent toutes les occurrences du caractère même . Cela signifie que vous ne pouvez supprimer qu'une série de blancs ou une série de points, par exemple.

Pour ce faire, vous pouvez utiliser une expression régulière à remplacer:

string s1 = "This is a sentence.TRIMTHIS";
string s2 = System.Text.RegularExpressions.Regex.Replace(s1, @"TRIMTHIS$", "");

Vous pouvez l'envelopper dans une méthode d'extension pour plus de commodité:

public static string TrimStringEnd(this string text, string removeThis)
{
    return System.Text.RegularExpressions.Regex.Replace(s1, removeThis, "");
}

Et appelez ça comme ça

string s2 = (@"This is a sentence.TRIMTHIS").TrimStringEnd(@"TRIMTHIS");
0
splattne

Voici la méthode d'extension que j'ai proposée (grande inspiration tirée des réponses existantes à cette question) pour compléter la méthode TrimEnd existante; il faut un booléen facultatif permettant de ne supprimer qu'une instance de la chaîne au lieu de toutes les instances de la fin.

/// <summary>
/// Removes trailing occurrence(s) of a given string from the current System.String object.
/// </summary>
/// <param name="trimSuffix">A string to remove from the end of the current System.String object.</param>
/// <param name="removeAll">If true, removes all trailing occurrences of the given suffix; otherwise, just removes the outermost one.</param>
/// <returns>The string that remains after removal of suffix occurrence(s) of the string in the trimSuffix parameter.</returns>
public static string TrimEnd(this string input, string trimSuffix, bool removeAll = true) {
    while (input != null && trimSuffix != null && input.EndsWith(trimSuffix)) {
        input = input.Substring(0, input.Length - trimSuffix.Length);

        if (!removeAll) {
            return input;
        }
    }

    return input;
}
0
Jez

J'ai récemment eu besoin d'un moyen très performant pour supprimer une ou plusieurs instances d'une chaîne du début/de la fin d'une chaîne. Cette implémentation que j'ai proposée est O(n) sur la longueur de la chaîne, évite les allocations coûteuses et n'appelle pas du tout SubString en utilisant un span.

Non Substring bidouille! (Eh bien, maintenant que j'ai édité mon post).

    public static string Trim(this string source, string whatToTrim, int count = -1) 
        => Trim(source, whatToTrim, true, true, count);

    public static string TrimStart(this string source, string whatToTrim, int count = -1) 
        => Trim(source, whatToTrim, true, false, count);

    public static string TrimEnd(this string source, string whatToTrim, int count = -1) 
        => Trim(source, whatToTrim, false, true, count);

    public static string Trim(this string source, string whatToTrim, bool trimStart, bool trimEnd, int numberOfOccurrences)
    {
        // source.IsNotNull(nameof(source));  <-- guard method, define your own
        // whatToTrim.IsNotNull(nameof(whatToTrim));  <-- "

        if (numberOfOccurrences == 0 
            || (!trimStart && !trimEnd) 
            || whatToTrim.Length == 0 
            || source.Length < whatToTrim.Length)
            return source;

        int start = 0, end = source.Length - 1, trimlen = whatToTrim.Length;

        if (trimStart)
            for (int count = 0; start < source.Length; start += trimlen, count++)
            {
                if (numberOfOccurrences > 0 && count == numberOfOccurrences)
                    break;
                for (int i = 0; i < trimlen; i++)
                    if ((source[start + i] != whatToTrim[i] && i != trimlen) || source.Length - start < trimlen)
                        goto DONESTART;
            }

        DONESTART:
        if (trimEnd)
            for (int count = 0; end > -1; end -= trimlen, count++)
            {
                if (numberOfOccurrences != -1 && count == numberOfOccurrences)
                    break;

                for (int i = trimlen - 1; i > -1; --i)
                    if ((source[end - trimlen + i + 1] != whatToTrim[i] && i != 0) || end - start + 1 < trimlen)
                        goto DONEEND;
            }

        DONEEND:
        return source.AsSpan().Slice(start, end - start + 1).ToString();
    }
0
CRAGIN