문자열을 줄로 분할하는 가장 좋은 방법
다중 줄 문자열을 줄로 분할하는 방법은 무엇입니까?
나는 이 방법을 알고 있습니다.
var result = input.Split("\n\r".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
약간 못생기고 빈 줄이 없어요.더 좋은 해결책이 있습니까?
보기 흉하면 불필요한 것을 제거합니다.
ToCharArray
불러.다음 중 하나로 분할하려면
\n
또는\r
두 가지 옵션이 있습니다.배열 리터럴을 사용합니다. 하지만 이렇게 하면 Windows 스타일의 줄 끝에 빈 줄이 표시됩니다.
\r\n
:var result = text.Split(new [] { '\r', '\n' });
Bart에 표시된 대로 정규식을 사용합니다.
var result = Regex.Split(text, "\r\n|\r|\n");
만약 당신이 빈 줄을 보존하고 싶다면, 왜 당신은 C#에게 그것들을 버리라고 명시적으로 말하는가? (
StringSplitOptions
매개 변수) – 사용StringSplitOptions.None
대신.
using (StringReader sr = new StringReader(text)) {
string line;
while ((line = sr.ReadLine()) != null) {
// do something
}
}
업데이트: 대체/비동기화 솔루션은 여기를 참조하십시오.
이것은 Regex보다 더 빠르고 잘 작동합니다.
input.Split(new[] {"\r\n", "\r", "\n"}, StringSplitOptions.None)
갖는 것은 중요합니다."\r\n"
한 줄 바꿈으로 간주되도록 배열에서 첫 번째.위의 내용은 다음 Regex 솔루션과 동일한 결과를 제공합니다.
Regex.Split(input, "\r\n|\r|\n")
Regex.Split(input, "\r?\n|\r")
Regex가 약 10배 느리다는 것만 빼면요.제 테스트는 다음과 같습니다.
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")
);
출력:
00:00:03.8527616
00:00:31.8017726
00:00:32.5557128
확장 방법은 다음과 같습니다.
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);
}
}
용도:
input.GetLines() // keeps empty lines
input.GetLines(true) // removes empty lines
Regex를 사용할 수 있습니다.분할:
string[] tokens = Regex.Split(input, @"\r?\n|\r");
편집: 추가됨|\r
(이전의) Mac 라인 터미네이터를 설명합니다.
빈 줄을 유지하려면 StringSplitOptions(StringSplit옵션)를 제거하면 됩니다.
var result = input.Split(System.Environment.NewLine.ToCharArray());
string[] lines = input.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
저는 다른 답을 가지고 있었지만, 잭의 대답에 따르면, 이것은 약간 느리긴 하지만 비동기식으로 작동하기 때문에 훨씬 더 빠를 수 있습니다.
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;
}
}
}
}
용도:
input.GetLines() // keeps empty lines
input.GetLines(true) // removes empty lines
테스트:
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()
);
출력:
00:00:03.9603894
00:00:00.0029996
00:00:04.8221971
약간 비틀리지만 반복기 블록을 사용합니다.
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);
}
그런 다음 전화할 수 있습니다.
var result = input.Lines().ToArray();
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();
}
혼합된 줄 끝을 제대로 처리하기가 어렵습니다.아시다시피, 회선 종료 문자는 "Line Feed"(ASCII 10,\n
,\x0A
,\u000A
), "캐리지 리턴"(ASCII 13,\r
,\x0D
,\u000D
) 또는 이들의 조합.DOS로 돌아가서 Windows는 CR-LF라는 두 문자 시퀀스를 사용합니다.\u000D\u000A
따라서 이 조합은 한 줄만 방출해야 합니다.Unix는 단일 제품을 사용합니다.\u000A
그리고 아주 오래된 Mac은 싱글을 사용했습니다.\u000D
성격.단일 텍스트 파일 내에서 이러한 문자의 임의 혼합을 처리하는 표준 방법은 다음과 같습니다.
- 각 CR 또는 LF 문자는 다음 줄로 건너뜁니다. 단...
- ...CR 직후에 LF(
\u000D\u000A
그러면 이 두 개가 함께 한 줄만 건너뜁니다. String.Empty
라인을 반환하지 않는 유일한 입력입니다(문자는 적어도 한 줄 이상 포함).- CR도 LF도 없는 경우에도 마지막 줄을 반환해야 합니다.
앞의 규칙은 StringReader의 동작을 설명합니다.ReadLine 및 관련 기능을 사용하면 아래 표시된 기능과 동일한 결과가 생성됩니다.이는 CR/LF의 임의 시퀀스 또는 조합을 올바르게 처리하기 위해 이러한 지침을 의무적으로 구현하는 효율적인 C# 줄 바꿈 기능입니다.열거된 줄에 CR/LF 문자가 없습니다.빈 줄은 보존되고 다음과 같이 반환됩니다.String.Empty
.
/// <summary>
/// Enumerates the text lines from the string.
/// ⁃ Mixed CR-LF scenarios are handled correctly
/// ⁃ String.Empty is returned for each empty line
/// ⁃ No returned string ever contains CR or LF
/// </summary>
public static IEnumerable<String> Lines(this String s)
{
int j = 0, c, i;
char ch;
if ((c = s.Length) > 0)
do
{
for (i = j; (ch = s[j]) != '\r' && ch != '\n' && ++j < c;)
;
yield return s.Substring(i, j - i);
}
while (++j < c && (ch != '\r' || s[j] != '\n' || ++j < c));
}
참고: 파일을 생성하는 데 드는 비용이 문제가 되지 않는다면StringReader
각 호출에 대해 다음 C#7 코드를 대신 사용할 수 있습니다.앞서 언급한 바와 같이, 위의 예제가 약간 더 효율적일 수 있지만, 이 두 기능 모두 정확하게 동일한 결과를 생성합니다.
public static IEnumerable<String> Lines(this String s)
{
using (var tr = new StringReader(s))
while (tr.ReadLine() is String L)
yield return L;
}
할당 없이 문자열을 여러 줄로 분할합니다.
public static LineEnumerator GetLines(this string text) {
return new LineEnumerator( text.AsSpan() );
}
internal ref struct LineEnumerator {
private ReadOnlySpan<char> Text { get; set; }
public ReadOnlySpan<char> Current { get; private set; }
public LineEnumerator(ReadOnlySpan<char> text) {
Text = text;
Current = default;
}
public LineEnumerator GetEnumerator() {
return this;
}
public bool MoveNext() {
if (Text.IsEmpty) return false;
var index = Text.IndexOf( '\n' ); // \r\n or \n
if (index != -1) {
Current = Text.Slice( 0, index + 1 );
Text = Text.Slice( index + 1 );
return true;
} else {
Current = Text;
Text = ReadOnlySpan<char>.Empty;
return true;
}
}
}
파티에 늦었지만, 나는 단지 그것을 위해 간단한 확장 방법 모음을 사용해왔고, 그것은 활용합니다.TextReader.ReadLine()
:
public static class StringReadLinesExtension
{
public static IEnumerable<string> GetLines(this string text) => GetLines(new StringReader(text));
public static IEnumerable<string> GetLines(this Stream stm) => GetLines(new StreamReader(stm));
public static IEnumerable<string> GetLines(this TextReader reader) {
string line;
while ((line = reader.ReadLine()) != null)
yield return line;
reader.Dispose();
yield break;
}
}
코드를 사용하는 것은 정말 사소한 일입니다.
// If you have the text as a string...
var text = "Line 1\r\nLine 2\r\nLine 3";
foreach (var line in text.GetLines())
Console.WriteLine(line);
// You can also use streams like
var fileStm = File.OpenRead("c:\tests\file.txt");
foreach(var line in fileStm.GetLines())
Console.WriteLine(line);
이것이 누군가에게 도움이 되길 바랍니다.
언급URL : https://stackoverflow.com/questions/1508203/best-way-to-split-string-into-lines
'programing' 카테고리의 다른 글
Docker 및 MariaDB/MySQL - 원격 액세스를 사용하도록 my.cnf를 영구적으로 편집 (0) | 2023.08.13 |
---|---|
Mocking boto3 S3 클라이언트 메소드 Python (0) | 2023.08.13 |
standard_init_linux.go:190: exec 사용자 프로세스로 인해 "해당 파일 또는 디렉터리가 없습니다" - 도커 (0) | 2023.08.13 |
git 설명이 실패하고 "failure:이름을 찾을 수 없고, 어떤 것도 설명할 수 없습니다." (0) | 2023.08.13 |
Android의 전체 화면 대화 상자 조각 (0) | 2023.08.13 |