Get Substring - tout avant certains caractères


124

J'essaie de trouver la meilleure façon d'obtenir tout avant le caractère - dans une chaîne. Quelques exemples de chaînes sont ci-dessous. La longueur de la chaîne avant - varie et peut être de n'importe quelle longueur

223232-1.jpg
443-2.jpg
34443553-5.jpg

donc j'ai besoin de la valeur qui va de l'index de début de 0 à juste avant -. Ainsi, les sous-chaînes s'avéreraient être 223232, 443 et 34443553

Réponses:


144

Exemple de .Net Fiddle

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("223232-1.jpg".GetUntilOrEmpty());
        Console.WriteLine("443-2.jpg".GetUntilOrEmpty());
        Console.WriteLine("34443553-5.jpg".GetUntilOrEmpty());

        Console.ReadKey();
    }
}

static class Helper
{
    public static string GetUntilOrEmpty(this string text, string stopAt = "-")
    {
        if (!String.IsNullOrWhiteSpace(text))
        {
            int charLocation = text.IndexOf(stopAt, StringComparison.Ordinal);

            if (charLocation > 0)
            {
                return text.Substring(0, charLocation);
            }
        }

        return String.Empty;
    }
}

Résultats:

223232
443
34443553
344

34

2
S'il vous plaît, rendez-leur service et ajoutez également une vérification des erreurs en supposant qu'il envisage d'en faire une fonction :)
Josh

Merci, j'étais proche de cela, mais j'étais curieux de savoir si quelqu'un avait une autre façon de le faire que ce combo. Mais oui, cela fonctionne très bien et est encore assez court.
PositiveGuy

14
Si vous vouliez un one-liner sans perdre la vérification appropriée «non trouvé», vous pouvez faire quelque chose comme ceci:string result = source.Substring(0, Math.Max(source.IndexOf('-'), 0))
LukeH

2
Au lieu de cela, s.Substring(0, n)on peut utiliser s.Remove(n)quand on sait (comme ici) que la longueur de la chaîne sdépasse strictement n.
Jeppe Stig Nielsen

@LukeH Si IndexOf renvoie -1 dans votre exemple, alors une chaîne vide serait renvoyée, n'est-ce pas?
écraser le

124

Utilisez la fonction de fractionnement .

static void Main(string[] args)
{
    string s = "223232-1.jpg";
    Console.WriteLine(s.Split('-')[0]);
    s = "443-2.jpg";
    Console.WriteLine(s.Split('-')[0]);
    s = "34443553-5.jpg";
    Console.WriteLine(s.Split('-')[0]);

Console.ReadKey();
}

Si votre chaîne n'a pas de chaîne, -vous obtiendrez la chaîne entière.


4
Et si vous avez plus d'un trait d'union, vous obtenez plusieurs éléments dans votre tableau.
James Dunne

2
En effet, James, ce ne serait donc une solution que si vous vous attendiez à un seul tiret. Je suppose que vous pouvez utiliser des méthodes Linq comme skip et agréger pour obtenir ce que vous vouliez, mais vous avez alors plus de code que les méthodes qui ont déjà été proposées. Tout dépend de vos connaissances sur les données entrantes.
Dominic Cronin

7
Et quelques années plus tard, je viens de me rendre compte que j'étais plutôt trop rapide pour concéder le point de James. La question demande comment trouver la chaîne avant un certain caractère. D'autres instances de ce caractère ne sont donc pas pertinentes, et prendre [0] "fonctionnerait simplement". Bien sûr, cela dépend toujours de la confiance que nous accordons aux données entrantes. Et s'il n'y a pas du tout de «-»?
Dominic Cronin

1
Je pense que le point de @JamesDunne était qu'en divisant en un tableau, vous créez un tas de chaînes inutiles - des déchets inutiles.
écraser le

1
Je ne m'inquiéterais pas des «déchets inutiles». Toutes les chaînes supplémentaires créées de cette manière seraient immédiatement inaccessibles et donc collectées à la génération 0, ce qui est en effet une surcharge extrêmement faible. La conception du ramasse-miettes est explicitement conçue pour permettre l'utilisation d'un grand nombre d'éléments de courte durée sans presque aucune dépense.
Dominic Cronin

65
String str = "223232-1.jpg"
int index = str.IndexOf('-');
if(index > 0) {
    return str.Substring(0, index)
}

upvote car j'ai besoin de connaître l'index du séparateur
Piero Alberto

3
C'est en fait la même réponse que Fredou a donnée (actuellement la réponse la plus élevée) sauf qu'elle omet de gérer le cas où aucune correspondance n'est trouvée.
Dominic Cronin

7

Les choses ont un peu évolué depuis le début de ce fil.

Maintenant, vous pouvez utiliser

string.Concat(s.TakeWhile((c) => c != '-'));

Comment cela compare-t-il les performances à la combinaison évidente IndexOf et Substring? Je suppose qu'il ajoute chaque caractère à un StringBuilder, puis produit une chaîne à la fin. Il y a aussi quelques appels de fonction mélangés. Cela aurait été bien si Substring pouvait simplement prendre -1 comme argument "longueur" signifiant "fin de chaîne".
écraser le

1
C'est pire pour l'efficacité. Comme vous le dites, il utilise un générateur de chaîne, et après avoir inspecté le code, il semble appeler ToString sur chaque caractère. C'est plus clair si vous recherchez plus d'un caractère, car vous pouvez réécrire facilement le lambda.
Anthony Wieser

5

Une façon de procéder consiste à utiliser String.Substringavec String.IndexOf:

int index = str.IndexOf('-');
string sub;
if (index >= 0)
{
    sub = str.Substring(0, index);
}
else
{
    sub = ... // handle strings without the dash
}

À partir de la position 0, renvoie tout le texte jusqu'au tiret, mais non compris.


si index <= 0, vous devez simplement renvoyer string.empty.
Aucun remboursement Aucun retour

5
@NRNR: si vous le dites. Le PO connaît les exigences de l'entreprise, pas vous ou moi
Michael Petrotta

0

S'appuyant sur la réponse de BrainCore:

    int index = 0;   
    str = "223232-1.jpg";

    //Assuming we trust str isn't null 
    if (str.Contains('-') == "true")
    {
      int index = str.IndexOf('-');
    }

    if(index > 0) {
        return str.Substring(0, index);
    }
    else {
       return str;
    }

0

Vous pouvez utiliser des expressions régulières à cette fin, mais il est bon d'éviter des exceptions supplémentaires lorsque la chaîne d'entrée ne correspond pas à l'expression régulière.

Tout d'abord, pour éviter un mal de tête supplémentaire de s'échapper vers le modèle regex - nous pourrions simplement utiliser la fonction à cette fin:

String reStrEnding = Regex.Escape("-");

Je sais que cela ne fait rien - car "-" est la même chose que Regex.Escape("=") == "=", mais cela fera une différence par exemple si le caractère est @"\".

Ensuite, nous devons faire correspondre le début de la chaîne à la fin de la chaîne, ou alternativement si la fin n'est pas trouvée - alors rien ne correspond. (Chaîne vide)

Regex re = new Regex("^(.*?)" + reStrEnding);

Si votre application est critique en termes de performances - alors une ligne distincte pour le nouveau Regex, sinon - vous pouvez tout avoir sur une seule ligne.

Et enfin correspondre à la chaîne et extraire le modèle correspondant:

String matched = re.Match(str).Groups[1].ToString();

Et après cela, vous pouvez soit écrire une fonction séparée, comme cela a été fait dans une autre réponse, soit écrire une fonction lambda en ligne. J'ai écrit maintenant en utilisant les deux notations - fonction lambda en ligne (n'autorise pas le paramètre par défaut) ou appel de fonction séparé.

using System;
using System.Text.RegularExpressions;

static class Helper
{
    public static string GetUntilOrEmpty(this string text, string stopAt = "-")
    {
        return new Regex("^(.*?)" + Regex.Escape(stopAt)).Match(text).Groups[1].Value;
    }
}

class Program
{
    static void Main(string[] args)
    {
        Regex re = new Regex("^(.*?)-");
        Func<String, String> untilSlash = (s) => { return re.Match(s).Groups[1].ToString(); };

        Console.WriteLine(untilSlash("223232-1.jpg"));
        Console.WriteLine(untilSlash("443-2.jpg"));
        Console.WriteLine(untilSlash("34443553-5.jpg"));
        Console.WriteLine(untilSlash("noEnding(will result in empty string)"));
        Console.WriteLine(untilSlash(""));
        // Throws exception: Console.WriteLine(untilSlash(null));

        Console.WriteLine("443-2.jpg".GetUntilOrEmpty());
    }
}

Btw - changer le modèle de regex en "^(.*?)(-|$)"permettra de ramasser soit jusqu'au "-"modèle ou si le modèle n'a pas été trouvé - ramasser tout jusqu'à la fin de la chaîne.


0

La manière LINQy

String.Concat ("223232-1.jpg" .TakeWhile (c => c! = '-'))

(Mais, vous devez tester null;)

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.