Obtenga Substring: todo antes de ciertos caracteres


124

Estoy tratando de encontrar la mejor manera de obtener todo antes del carácter - en una cadena. Algunas cadenas de ejemplo están a continuación. La longitud de la cadena antes: varía y puede ser de cualquier longitud

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

así que necesito el valor que es desde el índice inicial de 0 hasta justo antes -. Entonces las subcadenas serían 223232, 443 y 34443553

Respuestas:


144

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

Resultados:

223232
443
34443553
344

34

2
Por favor, hágales un favor y agregue la comprobación de errores, suponiendo que planea hacer una función de esto :)
Josh

Gracias, estaba cerca de esto, pero tenía curiosidad por saber si alguien tenía una forma diferente de hacerlo que no fuera este combo. Pero sí, esto funciona muy bien y todavía es bastante corto.
PositiveGuy el

14
Si quisieras una frase sin perder la comprobación "no encontrada" adecuada, entonces podrías hacer algo como esto:string result = source.Substring(0, Math.Max(source.IndexOf('-'), 0))
LukeH

2
En lugar de s.Substring(0, n)uno se puede usar s.Remove(n)cuando se sabe (como aquí) que la longitud de la cadena sexcede estrictamente n.
Jeppe Stig Nielsen

@LukeH Si IndexOf devuelve -1 en su ejemplo, se devolvería una cadena vacía, ¿no?
aplastar

124

Utiliza la función de división .

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 su cadena no tiene una -, obtendrá la cadena completa.


44
Y si tiene más de un guión, obtendrá varios elementos en su matriz.
James Dunne

2
De hecho, James, así que esto solo sería una solución si esperara un solo guión. Supongo que podría usar métodos de Linq como omitir y agregar para obtener lo que quería, pero entonces tiene más código que los métodos que ya se han propuesto. Todo depende de cuánto sepa sobre los datos entrantes.
Dominic Cronin

77
Y unos años después, me acabo de dar cuenta de que fui demasiado rápido para reconocer el punto de James. La pregunta pregunta cómo encontrar la cadena antes de cierto carácter. Otras instancias de ese carácter son irrelevantes, y tomar [0] "simplemente funcionaría". Por supuesto, aún depende de cuánto confiemos en los datos entrantes. ¿Qué pasa si no hay '-' en absoluto?
Dominic Cronin

1
Creo que el punto de @JamesDunne fue que al dividirse en una matriz, estás creando un montón de cadenas innecesarias: basura innecesaria.
aplastar

1
No me preocuparía por la "basura innecesaria". Cualquier cadena adicional creada de esta manera sería inmediatamente inalcanzable y, por lo tanto, recopilada en la generación 0, que es una sobrecarga extremadamente baja. El diseño del recolector de basura tiene el propósito explícito de permitir el uso de grandes cantidades de artículos de corta vida sin casi ningún gasto.
Dominic Cronin

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

votar porque necesito saber el índice del separador
Piero Alberto

3
Esta es en realidad la misma respuesta que Fredou dio (actualmente la respuesta principal), excepto que omite el manejo del caso donde no se encuentra ninguna coincidencia.
Dominic Cronin

7

Las cosas han avanzado un poco desde que comenzó este hilo.

Ahora, podrías usar

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

¿Cómo se compara esto en cuanto al rendimiento con la combinación obvia de IndexOf y Substring? Supongo que agrega cada carácter a un StringBuilder y luego produce una cadena al final. También hay un par de llamadas de función mezcladas. Hubiera sido bueno si Substring pudiera simplemente tomar -1 como un argumento de "longitud" que significa "fin de cadena".
aplastar

1
Es peor por la eficiencia. Como usted dice, usa un generador de cadenas, y al haber inspeccionado el código parece llamar a ToString en cada carácter. Es más claro si está buscando más de un personaje, ya que podría reescribir la lambda fácilmente.
Anthony Wieser

4

Una forma de hacerlo es usarlo String.Substringjunto con String.IndexOf:

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

Comenzando en la posición 0, devuelva todo el texto hasta el guión, pero sin incluirlo.


si index <= 0 solo debe devolver string.empty.
Sin reembolsos Sin devoluciones

55
@NRNR: si tú lo dices. El OP conoce los requisitos del negocio, no usted o yo
Michael Petrotta

0

Basándose en la respuesta 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

Puede usar expresiones regulares para este propósito, pero es bueno evitar excepciones adicionales cuando la cadena de entrada no coincide con la expresión regular.

Primero para evitar el dolor de cabeza adicional de escapar al patrón regex: podríamos usar la función para ese propósito:

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

Sé que esto no hace nada, ya que "-" es lo mismo que Regex.Escape("=") == "=", pero hará la diferencia, por ejemplo, si el personaje lo es @"\".

Luego, debemos hacer coincidir desde el inicio de la secuencia hasta el final de la secuencia, o alternativamente, si no se encuentra el final, no coincida con nada. (Cuerda vacía)

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

Si su aplicación es crítica para el rendimiento, entonces separe la línea para el nuevo Regex, si no, puede tener todo en una línea.

Y, finalmente, hacer coincidir con la cadena y extraer el patrón coincidente:

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

Y después de eso, puede escribir una función separada, como se hizo en otra respuesta, o escribir una función lambda en línea. Escribí ahora usando ambas notaciones: función lambda en línea (no permite el parámetro predeterminado) o llamada de función separada.

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

Por cierto, cambiar el patrón de expresión regular para "^(.*?)(-|$)"permitir recoger hasta el "-"patrón o si no se encontró el patrón, recoger todo hasta el final de la cadena.


0

La manera LINQy

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

(Pero, necesita probar nulo;)

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.