2012-04-30 1 views
2

Windows Forms C# 응용 프로그램에서 사용자가 로그 데이터를 붙여 넣은 텍스트 상자가 있고 정렬됩니다. 개별 라인을 개별적으로 검사하여 새 라인으로 입력을 분할해야하지만, 100,000 개가 넘는 많은 행이 있으면 OutOfMemoryException이 발생합니다.문자열 배열이 큰 여러 줄 항목에 대해 OutOfMemoryException을 throw합니다.

내 코드는 다음과 같습니다

StringSplitOptions splitOptions = new StringSplitOptions(); 
if(removeEmptyLines_CB.Checked) 
    splitOptions = StringSplitOptions.RemoveEmptyEntries; 
else 
    splitOptions = StringSplitOptions.None; 

List<string> outputLines = new List<string>(); 

foreach(string line in input_TB.Text.Split(new string[] { "\r\n", "\n" }, splitOptions)) 
{ 
    if(line.Contains(inputCompare_TB.Text)) 
     outputLines.Add(line); 
} 
output_TB.Text = string.Join(Environment.NewLine, outputLines); 

문제는 input_TB.Text.Split(new string[] { "\r\n", "\n" }

이 작업을 수행 할 수있는 더 나은 방법이 있나요 여기, 내가 라인으로 텍스트 상자의 텍스트를 분할하는 경우에서 온다? 텍스트의 첫 번째 X 분량을 가져다가 새 줄을 자르고 모든 내용을 읽을 때까지 반복하는 방법을 생각해 보았지만 지루한 것처럼 보입니다. 아니면 더 많은 메모리를 할당 할 수있는 방법이 있습니까?

덕분에, 개렛

업데이트 아틸라에

덕분에, 나는이 함께 와서 그것을 작동하는 것 같다. 감사합니다

StringReader reader = new StringReader(input_TB.Text); 
string line; 
while((line = reader.ReadLine()) != null) 
{ 
    if(line.Contains(inputCompare_TB.Text)) 
     outputLines.Add(line); 
} 
output_TB.Text = string.Join(Environment.NewLine, outputLines); 

답변

2

결과를 만들 추출하고 한 번에 하나 개의 라인을 처리하고, StringBuilder을 사용하는 것이 작업을 수행 할 수있는 더 좋은 방법 :

StringBuilder outputTxt = new StringBuilder(); 
string txt = input_TB.Text; 
int txtIndex = 0; 
while (txtIndex < txt.Length) { 
    int startLineIndex = txtIndex; 
GetMore: 
    while (txtIndex < txt.Length && txt[txtIndex] != '\r' && txt[txtIndex] != '\n')) { 
    txtIndex++; 
    } 
    if (txtIndex < txt.Length && txt[txtIndex] == '\r' && (txtIndex == txt.Length-1 || txt[txtIndex+1] != '\n') { 
    txtIndex++; 
    goto GetMore; 
    } 
    string line = txt.Substring(startLineIndex, txtIndex-startLineIndex); 
    if (line.Contains(inputCompare_TB.Text)) { 
    if (outputTxt.Length > 0) 
     outputTxt.Append(Environment.NewLine); 
    outputTxt.Append(line); 
    } 
    txtIndex++; 
} 
output_TB.Text = outputTxt.ToString(); 

선제 코멘트 : 누군가가 goto에 반대합니다 - 하지만 훨씬 청소기 솔루션 인 라인을 분할하는 StringReader을 사용하여 다른 루프 continue 또는 break

에 (REG의 예를 들어 특급), 또는 가짜 고토, 대안은 훨씬 더 복잡하다 여기에서 필요한하지만, 그것은 손에하지 않는다. 르 새로운 라인 등 모두 \r\n\n :

StringReader reader = new StringReader(input_TB.Text); 
StringBuilder outputTxt = new StringBuilder(); 
string compareTxt = inputCompare_TB.Text; 
string line; 
while((line = reader.ReadLine()) != null) { 
    if (line.Contains(compareTxt)) { 
    if (outputTxt.Length > 0) 
     outputTxt.Append(Environment.NewLine); 
    outputTxt.Append(line); 
    } 
} 
output_TB.Text = outputTxt.ToString(); 
+0

나는 C#에서 goto 문을 사용할 수 있다는 것을 몰랐다. 파스칼하고 기본적이고 재미있는 게임을 한 아이 였을 때부터 사용하지 않았다고 생각하지 않는다.이것은 지나치게 복잡해 보이지만 제 질문에 대한 업데이트를 살펴보십시오. –

+0

내 답변 끝에 메모를 추가했습니다. 귀하의 업데이트는 깨끗하지만'\ r \ n'과'\ n'을 끝 줄로 처리하지 않습니다. 만약 당신이 그걸로 도망 갈 수 있다면 괜찮아요. - 나는 여전히 StringBuilder를 사용하여 (큰?) 중간 문자열 목록을 만드는 것을 피하는 것이 좋습니다. – MiMo

+0

예,'goto'는 C#에서 가능하며,이 경우처럼 - sparingly - 사용합니다. – MiMo

3

Split 각 줄의 메모리 원본 텍스트의 필요, 플러스 string 객체의 오버 헤드를 복제해야합니다. 이것이 메모리 문제를 일으키는 경우, 입력을 처리하는 신뢰할 수있는 방법은 한 번에 한 행을 구문 분석하는 것입니다.

+0

덕분에, 내 업데이 트를 살펴보고 그 당신이 무엇을 의미하는지 경우 알려주세요. 나는 이것을 곧 답변 할 것이라고 표시 할 것이고, 나는 단지 몇 가지 다른 아이디어를보고 싶다. 다시 한 번 감사드립니다! –

0

대용량 텍스트 파일에서이 작업을 수행하는 유일한 방법은 수동으로 파일을 열고 StreamReader을 사용하는 것입니다. Here은이를 수행하는 방법의 예입니다.

0

한 번에 각 라인 하나의 캐릭터를 생성하여 모든 라인과 배열의 문자열을 생성 피할 수 : 한편

var eol = new[] { '\r', '\n' }; 

var pos = 0; 
while (pos < input.Length) 
{ 
    var i = input.IndexOfAny(eol, pos); 
    if (i < 0) 
    { 
     i = input.Length; 
    } 
    if (i != pos) 
    { 
     var line = input.Substring(pos, i - pos); 

     // process line 
    } 
    pos = i + 1; 
} 
0

In this article는 점 "분할"방법이 있다는 것을 말한다 저조한 실행. 그것을 읽고 결론을 내십시오.

아틸라 (Attila)와 마찬가지로, 당신은 줄 단위로 구문 분석해야합니다.

관련 문제