Moyen le plus simple de diviser une chaîne sur les retours à la ligne in.NET?
J'ai besoin de diviser une chaîne en sauts de ligne dans.NET et la seule façon que je connaisse de diviser les chaînes est avec la méthode Split. Cependant, cela ne me permettra pas de (facilement) diviser sur une nouvelle ligne, alors quelle est la meilleure façon de le faire?
15 réponses
Pour diviser sur une chaîne, vous devez utiliser la surcharge qui prend un tableau de chaînes:
string[] lines = theText.Split(
new[] { Environment.NewLine },
StringSplitOptions.None
);
Modifier:
Si vous souhaitez gérer différents types de sauts de ligne dans un texte, vous pouvez utiliser la possibilité de faire correspondre plus d'une chaîne. Cela se divisera correctement sur l'un ou l'autre type de saut de ligne, et préservera les lignes vides et l'espacement dans le texte:
string[] lines = theText.Split(
new[] { "\r\n", "\r", "\n" },
StringSplitOptions.None
);
Qu'en est-il de l'utilisation d'un StringReader
?
using (System.IO.StringReader reader = new System.IO.StringReader(input)) {
string line = reader.ReadLine();
}
Vous devriez pouvoir diviser votre chaîne assez facilement, comme ceci:
aString.Split(Environment.NewLine.ToCharArray());
Basé sur la réponse de Guffa, dans une classe d'extension, Utilisez:
public static string[] Lines(this string source) {
return source.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None);
}
Essayez d'éviter d'utiliser de la chaîne.Split pour une solution générale, car vous utiliserez plus de mémoire partout où vous utiliserez la fonction-la chaîne d'origine, et la copie fractionnée, à la fois en mémoire. Croyez-moi que cela peut être un sacré problème lorsque vous commencez à mettre à l'échelle-exécutez une application de traitement par lots 32 bits traitant des documents 100MB, et vous allez chier à Huit threads simultanés. Non pas que j'ai été là avant...
À la place, utilisez un itérateur comme celui-ci;
public static IEnumerable<string> SplitToLines(this string input)
{
if (input == null)
{
yield break;
}
using (System.IO.StringReader reader = new System.IO.StringReader(input))
{
string line;
while( (line = reader.ReadLine()) != null)
{
yield return line;
}
}
}
Cela vous permettra de faire une boucle plus efficace en mémoire autour de vos données;
foreach(var line in document.SplitToLines())
{
// one line at a time...
}
Bien sûr, si vous le voulez tout en mémoire, vous pouvez le faire;
var allTheLines = document.SplitToLines.ToArray();
Pour une variable de chaîne s
:
s.Split(new string[]{Environment.NewLine},StringSplitOptions.None)
Cela utilise la définition des fins de ligne de votre environnement. Sous Windows, les fins de ligne sont CR-LF (retour chariot, saut de ligne) ou dans les caractères d'échappement de C#\r\n
.
C'est une solution fiable, car si vous recombinez les lignes avec String.Join
, ceci est égal à votre chaîne d'origine:
var lines = s.Split(new string[]{Environment.NewLine},StringSplitOptions.None);
var reconstituted = String.Join(Environment.NewLine,lines);
Debug.Assert(s==reconstituted);
Ce qu'il ne faut pas faire:
- Utilisation
StringSplitOptions.RemoveEmptyEntries
, parce que cela va casser le balisage tel que Markdown où les lignes vides ont syntaxique but. - Split sur separator
new char[]{Environment.NewLine}
, car sous Windows, cela créera un élément de chaîne vide pour chaque nouvelle ligne.
Regex est également une option:
private string[] SplitStringByLineFeed(string inpString)
{
string[] locResult = Regex.Split(inpString, "[\r\n]+");
return locResult;
}
Je pensais juste ajouter mes deux bits parce que les autres solutions sur cette question ne tombent pas dans la classification de code réutilisable et ne sont pas pratiques. Le bloc de code suivant étend l'objet string
afin qu'il soit disponible en tant que méthode naturelle lorsque vous travaillez avec des chaînes.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
using System.Collections.ObjectModel;
namespace System
{
public static class StringExtensions
{
public static string[] Split(this string s, string delimiter, StringSplitOptions options = StringSplitOptions.None)
{
return s.Split(new string[] { delimiter }, options);
}
}
}
Vous pouvez maintenant utiliser la fonction .Split()
de n'importe quelle chaîne comme suit:
string[] result;
// pass a string, and the delimiter
result = string.Split("My simple string", " ");
// split an existing string by delimiter only
string foo = "my - string - i - want - split";
result = foo.Split("-");
// you can even pass the split options param. when omitted it is
// set to StringSplitOptions.None
result = foo.Split("-", StringSplitOptions.RemoveEmptyEntries);
Pour diviser sur un caractère de nouvelle ligne, passez simplement "\n"
ou "\r\n"
comme paramètre de délimiteur.
Commentaire : Ce serait bien si Microsoft implémentait cette surcharge.
J'utilise actuellement cette fonction (basée sur d'autres réponses) dans VB.NET:
Private Shared Function SplitLines(text As String) As String()
Return text.Split({Environment.NewLine, vbCrLf, vbLf}, StringSplitOptions.None)
End Function
Il essaie d'abord de diviser sur la nouvelle ligne locale de la plate-forme, puis revient à chaque nouvelle ligne possible.
J'ai seulement eu besoin de cela dans une classe jusqu'à présent. Si cela change, je vais probablement faire ceci Public
et le déplacer vers une classe utilitaire, et peut-être même en faire une méthode d'extension.
Voici comment rejoindre les lignes, pour faire bonne mesure:
Private Shared Function JoinLines(lines As IEnumerable(Of String)) As String
Return String.Join(Environment.NewLine, lines)
End Function
Eh bien, en fait split devrait faire:
//Constructing string...
StringBuilder sb = new StringBuilder();
sb.AppendLine("first line");
sb.AppendLine("second line");
sb.AppendLine("third line");
string s = sb.ToString();
Console.WriteLine(s);
//Splitting multiline string into separate lines
string[] splitted = s.Split(new string[] {System.Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries);
// Output (separate lines)
for( int i = 0; i < splitted.Count(); i++ )
{
Console.WriteLine("{0}: {1}", i, splitted[i]);
}
string[] lines = text.Split(
Environment.NewLine.ToCharArray(),
StringSplitOptions.RemoveEmptyStrings);
L'option RemoveEmptyStrings s'assurera que vous n'avez pas d'entrées vides en raison de \n suivant un \ r
(Modifier pour refléter les commentaires:) notez qu'il supprimera également les lignes vides authentiques dans le texte. C'est généralement ce que je veux, mais ce n'est peut-être pas votre exigence.
Je ne connaissais pas L'environnement.Nouvelle ligne, mais je suppose que c'est une très bonne solution.
Mon essai aurait été:
string str = "Test Me\r\nTest Me\nTest Me";
var splitted = str.Split('\n').Select(s => s.Trim()).ToArray();
Le supplément .Trim supprime tout \r ou \n qui pourrait être encore présent (par exemple sous windows, mais en divisant une chaîne avec des caractères de nouvelle ligne os x). Probablement pas la méthode la plus rapide mais.
Modifier:
Comme les commentaires l'ont correctement souligné, cela supprime également tout espace au début de la ligne ou avant le nouveau saut de ligne. Si vous avez besoin d' pour conserver cet espace, utilisez l'une des autres options.
Réponse Stupide: écrivez dans un fichier temporaire afin que vous puissiez utiliser le vénérable
File.ReadLines
var s = "Hello\r\nWorld";
var path = Path.GetTempFileName();
using (var writer = new StreamWriter(path))
{
writer.Write(s);
}
var lines = File.ReadLines(path);
// using System.IO;
string textToSplit;
if(textToSplit!=null)
{
List<string> lines = new List<string>();
using (StringReader reader = new StringReader(textToSplit))
{
for (string line = reader.ReadLine(); line != null;line = reader.ReadLine())
{
lines.Add(line);
}
}
}
Très facile, en fait.
VB.NET:
Private Function SplitOnNewLine(input as String) As String
Return input.Split(Environment.NewLine)
End Function
C#:
string splitOnNewLine(string input)
{
return input.split(environment.newline);
}