Ottieni sottostringa: tutto prima di un determinato carattere


124

Sto cercando di capire il modo migliore per ottenere tutto prima del carattere - in una stringa. Di seguito sono riportate alcune stringhe di esempio. La lunghezza della stringa prima di - varia e può essere qualsiasi lunghezza

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

quindi ho bisogno del valore che va dall'indice iniziale di 0 a subito prima di -. Quindi le sottostringhe risulterebbero essere 223232, 443 e 34443553

Risposte:


144

.Net Fiddle esempio

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

risultati:

223232
443
34443553
344

34

2
Per favore, fai loro un favore e aggiungi anche il controllo degli errori supponendo che abbia intenzione di creare una funzione da questo :)
Josh

Grazie, ero vicino a questo, ma ero curioso di sapere se qualcuno avesse un modo diverso di farlo oltre a questa combinazione. Ma sì, funziona alla grande ed è ancora piuttosto breve.
PositiveGuy

14
Se volevi una battuta senza perdere il controllo "non trovato" corretto, potresti fare qualcosa del genere:string result = source.Substring(0, Math.Max(source.IndexOf('-'), 0))
LukeH

2
Invece di s.Substring(0, n)uno può usare s.Remove(n)quando è noto (come qui) che la lunghezza della stringa è sstrettamente superiore n.
Jeppe Stig Nielsen

@LukeH Se IndexOf restituisce -1 nel tuo esempio, verrebbe restituita una stringa vuota, no?
schiacciare il

124

Usa la funzione split .

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

Se la tua stringa non ha un -, otterrai l'intera stringa.


4
E se hai più di un trattino, ottieni più elementi nel tuo array.
James Dunne

2
Infatti, James, quindi questa sarebbe una soluzione solo se ti aspettassi un solo trattino. Suppongo che potresti usare metodi Linq come salta e aggrega per ottenere ciò che desideri, ma poi hai più codice rispetto ai metodi che sono stati già proposti. Tutto dipende da quanto sai dei dati in arrivo.
Dominic Cronin

7
E alcuni anni dopo, mi sono appena reso conto di essere stato troppo veloce per ammettere il punto di James. La domanda chiede come trovare la stringa prima di un certo carattere. Ulteriori istanze di quel carattere sono quindi irrilevanti e prendere [0] "funzionerebbe". Naturalmente, dipende ancora da quanto ci fidiamo dei dati in arrivo. E se non ci fosse affatto "-"?
Dominic Cronin

1
Penso che il punto di @JamesDunne fosse che dividendo in un array, stai creando un mucchio di stringhe non necessarie - spazzatura inutile.
schiacciare il

1
Non mi preoccuperei di "spazzatura inutile". Eventuali stringhe extra create in questo modo sarebbero immediatamente irraggiungibili e quindi raccolte nella generazione 0, che è davvero un overhead estremamente basso. Il design del Garbage Collector è esplicitamente concepito per consentire l'utilizzo di un gran numero di elementi di breve durata con quasi nessuna spesa.
Dominic Cronin

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

voto positivo perché ho bisogno di sapere l'indice del separatore
Piero Alberto

3
Questa è in realtà la stessa risposta data da Fredou (attualmente la risposta migliore) tranne per il fatto che omette di gestire il caso in cui non viene trovata alcuna corrispondenza.
Dominic Cronin

7

Le cose sono cambiate un po 'dall'inizio di questo thread.

Ora potresti usare

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

In che modo questo confronta le prestazioni in termini di prestazioni con l'ovvia combinazione IndexOf e Substring? Presumo che stia aggiungendo ogni carattere a StringBuilder e quindi producendo una stringa alla fine. Ci sono anche un paio di chiamate di funzione mescolate. Sarebbe stato carino se Substring potesse semplicemente prendere -1 come argomento di "lunghezza" che significa "fine della stringa".
schiacciare il

1
È peggio per l'efficienza. Come dici tu, utilizza un generatore di stringhe e dopo aver ispezionato il codice sembra chiamare ToString su ogni carattere. È più chiaro se stai cercando più di un carattere, poiché potresti riscrivere facilmente il lambda.
Anthony Wieser

5

Un modo per farlo è usare String.Substringinsieme a String.IndexOf:

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

Partendo dalla posizione 0, riporta tutto il testo fino al trattino, ma escluso.


se index <= 0 dovresti semplicemente restituire string.empty.
Nessun rimborso Nessun reso

5
@NRNR: se lo dici tu. L'OP conosce i requisiti aziendali, non tu o io.
Michael Petrotta

0

Basandosi sulla risposta di 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

È possibile utilizzare espressioni regolari per questo scopo, ma è bene evitare eccezioni aggiuntive quando la stringa di input non corrisponde all'espressione regolare.

Prima di tutto per evitare un ulteriore mal di testa di sfuggire al pattern regex - potremmo semplicemente usare la funzione per quello scopo:

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

So che questo non fa nulla - poiché "-" è uguale a Regex.Escape("=") == "=", ma farà la differenza, ad esempio, se il carattere lo è @"\".

Quindi dobbiamo abbinare dall'accattonaggio della stringa alla fine della stringa, o in alternativa, se la fine non viene trovata, non corrispondere a nulla. (Stringa vuota)

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

Se la tua applicazione è critica per le prestazioni, quindi una riga separata per il nuovo Regex, in caso contrario, puoi avere tutto in una riga.

Infine, confronta la stringa ed estrai il modello corrispondente:

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

Dopodiché puoi scrivere una funzione separata, come è stato fatto in un'altra risposta, oppure scrivere una funzione lambda inline. Ho scritto ora usando entrambe le notazioni: funzione lambda inline (non consente il parametro predefinito) o chiamata di funzione separata.

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 - cambiare il pattern regex in "^(.*?)(-|$)"consentirà di riprendere fino al "-"pattern o se il pattern non è stato trovato - raccogliere tutto fino alla fine della stringa.


0

Il modo LINQy

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

(Ma devi testare per null;)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.