La mejor manera de dividir la cadena en líneas


¿Cómo se divide la cadena de varias líneas en líneas?

Sé de esta manera

var result = input.Split("\n\r".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);

Se ve un poco feo y pierde líneas vacías. Hay una solución mejor?

Author: Steve Chambers, 2009-10-02

9 answers

  • Si se ve feo, simplemente elimine la llamada innecesaria ToCharArray.

  • Si desea dividir por \n o \r, tienes dos opciones:

    • Use un array literal-pero esto le dará líneas vacías para las terminaciones de línea de estilo Windows \r\n:

      var result = text.Split(new [] { '\r', '\n' });
      
    • Use una expresión regular, como indica Bart:

      var result = Regex.Split(text, "\r\n|\r|\n");
      
  • Si desea conservar líneas vacías, ¿por qué le dice explícitamente a C# que las lance ¿lejos? (StringSplitOptions parámetro) - utilice StringSplitOptions.None en su lugar.

 128
Author: Konrad Rudolph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-03 08:42:59
using (StringReader sr = new StringReader(text)) {
    string line;
    while ((line = sr.ReadLine()) != null) {
        // do something
    }
}
 96
Author: Jack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-20 16:33:35

Puedes usar expresiones regulares.División:

string[] tokens = Regex.Split(input, @"\r?\n|\r");

Editar: se agregó |\r para tener en cuenta los terminadores de línea Mac (más antiguos).

 34
Author: Bart Kiers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-26 16:09:37

Actualizar: Ver aquí para una solución alternativa/asincrónica.


Esto funciona muy bien y es más rápido que Regex:

input.Split(new[] {"\r\n", "\r", "\n"}, StringSplitOptions.None)

Es importante tener "\r\n" primero en la matriz para que se tome como un salto de línea. Lo anterior da los mismos resultados que cualquiera de estas soluciones Regex:

Regex.Split(input, "\r\n|\r|\n")

Regex.Split(input, "\r?\n|\r")

Excepto que la expresión regular resulta ser aproximadamente 10 veces más lenta. Aquí está mi prueba:

Action<Action> measure = (Action func) => {
    var start = DateTime.Now;
    for (int i = 0; i < 100000; i++) {
        func();
    }
    var duration = DateTime.Now - start;
    Console.WriteLine(duration);
};

var input = "";
for (int i = 0; i < 100; i++)
{
    input += "1 \r2\r\n3\n4\n\r5 \r\n\r\n 6\r7\r 8\r\n";
}

measure(() =>
    input.Split(new[] {"\r\n", "\r", "\n"}, StringSplitOptions.None)
);

measure(() =>
    Regex.Split(input, "\r\n|\r|\n")
);

measure(() =>
    Regex.Split(input, "\r?\n|\r")
);

Salida:

00:00:03.8527616

00:00:31.8017726

00:00:32.5557128

Y aquí está el Método de extensión :

public static class StringExtensionMethods
{
        public static IEnumerable<string> GetLines(this string str, bool removeEmptyLines = false)
        {
            return str.Split(new[] { "\r\n", "\r", "\n" },
                removeEmptyLines ? StringSplitOptions.RemoveEmptyEntries : StringSplitOptions.None);
        }
}

Uso:

input.GetLines()      // keeps empty lines

input.GetLines(true)  // removes empty lines
 31
Author: orad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-01 23:45:30

Si desea mantener líneas vacías, simplemente elimine las StringSplitOptions.

var result = input.Split(System.Environment.NewLine.ToCharArray());
 5
Author: Jonas Elfström,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-02 07:57:23

Tenía esta otra respuesta pero esta, basada en la respuesta de Jack , es significativamente más rápido podría ser preferido ya que funciona asincrónicamente, aunque ligeramente más lento.

public static class StringExtensionMethods
{
    public static IEnumerable<string> GetLines(this string str, bool removeEmptyLines = false)
    {
        using (var sr = new StringReader(str))
        {
            string line;
            while ((line = sr.ReadLine()) != null)
            {
                if (removeEmptyLines && String.IsNullOrWhiteSpace(line))
                {
                    continue;
                }
                yield return line;
            }
        }
    }
}

Uso:

input.GetLines()      // keeps empty lines

input.GetLines(true)  // removes empty lines

Prueba:

Action<Action> measure = (Action func) =>
{
    var start = DateTime.Now;
    for (int i = 0; i < 100000; i++)
    {
        func();
    }
    var duration = DateTime.Now - start;
    Console.WriteLine(duration);
};

var input = "";
for (int i = 0; i < 100; i++)
{
    input += "1 \r2\r\n3\n4\n\r5 \r\n\r\n 6\r7\r 8\r\n";
}

measure(() =>
    input.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None)
);

measure(() =>
    input.GetLines()
);

measure(() =>
    input.GetLines().ToList()
);

Salida:

00:00:03.9603894

00:00:00.0029996

00:00:04.8221971

 4
Author: orad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-01 23:59:33

Ligeramente retorcido, pero un bloque iterador para hacerlo:

public static IEnumerable<string> Lines(this string Text)
{
    int cIndex = 0;
    int nIndex;
    while ((nIndex = Text.IndexOf(Environment.NewLine, cIndex + 1)) != -1)
    {
        int sIndex = (cIndex == 0 ? 0 : cIndex + 1);
        yield return Text.Substring(sIndex, nIndex - sIndex);
        cIndex = nIndex;
    }
    yield return Text.Substring(cIndex + 1);
}

Puedes llamar a:

var result = input.Lines().ToArray();
 2
Author: JDunkerley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-02 08:08:27
      char[] archDelim = new char[] { '\r', '\n' };
      words = asset.text.Split(archDelim, StringSplitOptions.RemoveEmptyEntries); 
 2
Author: MAG TOR,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-11 05:58:21
    private string[] GetLines(string text)
    {

        List<string> lines = new List<string>();
        using (MemoryStream ms = new MemoryStream())
        {
            StreamWriter sw = new StreamWriter(ms);
            sw.Write(text);
            sw.Flush();

            ms.Position = 0;

            string line;

            using (StreamReader sr = new StreamReader(ms))
            {
                while ((line = sr.ReadLine()) != null)
                {
                    lines.Add(line);
                }
            }
            sw.Close();
        }



        return lines.ToArray();
    }
 1
Author: John Thompson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-06 00:55:53