Get Substring - wszystko przed określonym char


125

Próbuję znaleźć najlepszy sposób, aby uzyskać wszystko przed znakiem - w ciągu. Poniżej znajdują się przykładowe ciągi znaków. Długość łańcucha przed - jest różna i może mieć dowolną długość

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

więc potrzebuję wartości od indeksu początkowego 0 do tuż przed -. Więc podciągami okazałyby się być 223232, 443 i 34443553

Odpowiedzi:


144

Przykład .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;
    }
}

Wyniki:

223232
443
34443553
344

34

2
Zrób im przysługę i dodaj również sprawdzanie błędów, zakładając, że planuje zrobić z tego funkcję :)
Josh

Dzięki, byłem blisko tego, ale byłem ciekawy, czy ktoś ma inny sposób na zrobienie tego inaczej niż ta kombinacja. Ale tak, to działa świetnie i nadal jest dość krótkie.
PositiveGuy,

14
Jeśli chcesz mieć jedną linijkę bez utraty właściwego sprawdzania „nie znaleziono”, możesz zrobić coś takiego:string result = source.Substring(0, Math.Max(source.IndexOf('-'), 0))
LukeH

2
Zamiast tego s.Substring(0, n)można użyć, s.Remove(n)gdy wiadomo (jak tutaj), że długość sznurka sściśle przekracza n.
Jeppe Stig Nielsen

@LukeH Jeśli IndexOf zwróci -1 w twoim przykładzie, to zostanie zwrócony pusty ciąg, prawda?
zmiażdżyć

124

Użyj funkcji podziału .

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

Jeśli twój ciąg nie ma -a, otrzymasz cały ciąg.


4
A jeśli masz więcej niż jeden łącznik, w tablicy znajduje się wiele elementów.
James Dunne

2
Rzeczywiście, James, więc byłoby to rozwiązanie tylko wtedy, gdybyś oczekiwał tylko jednego łącznika. Przypuszczam, że możesz użyć metod Linq, takich jak pomiń i agreguj, aby uzyskać to, czego chcesz, ale masz więcej kodu niż metod, które zostały już zaproponowane. Wszystko zależy od tego, ile wiesz o przychodzących danych.
Dominic Cronin

7
Po kilku latach właśnie zdałem sobie sprawę, że zbyt szybko zgodziłem się z opinią Jamesa. Pytanie dotyczy tego, jak znaleźć ciąg przed określonym znakiem. Dalsze przypadki tego znaku są zatem nieistotne, a zabranie [0] „po prostu zadziała”. Oczywiście nadal zależy to od tego, jak bardzo ufamy napływającym danym. A jeśli w ogóle nie ma „-”?
Dominic Cronin

1
Myślę, że @JamesDunne chodzi o to, że dzieląc się na tablicę, tworzysz zbędne ciągi - niepotrzebne śmieci.
zmiażdżyć

1
Nie martwiłbym się o „niepotrzebne śmieci”. Wszelkie dodatkowe ciągi utworzone w ten sposób byłyby natychmiast nieosiągalne i dlatego gromadzone w generacji 0, co jest rzeczywiście niezwykle niskim narzutem. Konstrukcja garbage collectora została wyraźnie zaprojektowana, aby umożliwić użycie dużej liczby krótkotrwałych elementów prawie bez żadnych kosztów.
Dominic Cronin

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

upvote bo muszę znać indeks separatora
Piero Alberto

3
W rzeczywistości jest to ta sama odpowiedź, której udzielił Fredou (obecnie najlepsza odpowiedź), z tym wyjątkiem, że pomija obsługę przypadku, w którym nie znaleziono dopasowania.
Dominic Cronin

7

Od początku tego wątku sytuacja trochę się zmieniła.

Teraz możesz użyć

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

Jak wypada to porównanie wydajności z oczywistą kombinacją IndexOf i Substring? Zakładam, że dołącza każdy znak do StringBuilder, a następnie tworzy ciąg na końcu. Jest też kilka wywołań funkcji. Byłoby miło, gdyby Substring mógł po prostu przyjąć -1 jako argument „length” oznaczający „koniec łańcucha”.
zmiażdżyć

1
Gorzej dla wydajności. Jak mówisz, używa konstruktora ciągów i po sprawdzeniu kodu wydaje się wywoływać ToString dla każdego znaku. Jest to wyraźniejsze, jeśli szukasz więcej niż jednego znaku, ponieważ możesz łatwo przepisać lambdę.
Anthony Wieser,

5

Jednym ze sposobów jest użycie String.Substringrazem z String.IndexOf:

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

Zaczynając od pozycji 0, zwróć cały tekst do kreski, ale bez niej.


jeśli indeks <= 0, powinieneś po prostu zwrócić string.empty.
Brak zwrotów Brak zwrotów

5
@NRNR: jeśli tak mówisz. OP zna wymagania biznesowe, nie ty czy ja
Michael Petrotta

0

Opierając się na odpowiedzi 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

W tym celu możesz użyć wyrażeń regularnych, ale dobrze jest unikać dodatkowych wyjątków, gdy ciąg wejściowy jest niezgodny z wyrażeniem regularnym.

Po pierwsze, aby uniknąć dodatkowego bólu głowy związanego z ucieczką do wzorca regex - możemy po prostu użyć funkcji do tego celu:

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

Wiem, że to nic nie robi - ponieważ "-" jest tym samym co Regex.Escape("=") == "=", ale będzie miało znaczenie, na przykład, jeśli znak jest@"\" .

Następnie musimy dopasować od początku ciągu do końca łańcucha lub na przemian, jeśli koniec nie zostanie znaleziony - wtedy nic nie dopasowujemy. (Pusta struna)

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

Jeśli Twoja aplikacja ma krytyczne znaczenie dla wydajności - to oddzielna linia dla nowego Regex, jeśli nie - możesz mieć wszystko w jednej linii.

I na koniec dopasuj do ciągu i wyodrębnij dopasowany wzorzec:

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

Następnie możesz albo napisać oddzielną funkcję, tak jak to było zrobione w innej odpowiedzi, lub napisać wbudowaną funkcję lambda. Napisałem teraz używając obu notacji - wbudowanej funkcji lambda (nie pozwala na domyślny parametr) lub oddzielnego wywołania funkcji.

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 - zmiana wzorca wyrażenia regularnego na "^(.*?)(-|$)"pozwoli podnieść albo do "-"wzorca, albo jeśli wzorzec nie został znaleziony - podnieś wszystko do końca łańcucha.


0

Sposób LINQy

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

(Ale musisz przetestować pod kątem null;)

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.