2016-08-29 3 views
0

데이터가 정확해야한다는 것을 알고 있습니다. 나는 데이터에 대한 통제권이 없으며, 상사는 다른 사람의 실수를 다루는 방법을 찾아야한다고 말하려고합니다. 그러니 제발 데이터가 나쁘다고 제 문제가 아니라고 말하지 마세요.나쁜 csv 데이터를 구문 분석하는 방법은 무엇입니까?

"Words","[email protected]","","4253","57574","FirstName","","LastName, MD","","","576JFJD","","1971","","Words","Address","SUITE "A"","City","State","Zip","Phone","","" 

데이터는 기밀을 이유로 하찮은되었습니다

됐건,이 내가 찾고 있어요 것입니다.

위와 같이 데이터에는 따옴표가 들어 있으며 인용 된 필드에는 쉼표가 있습니다. 그래서 나는 그들을 제거 할 수 없다. 그러나 "Suite A"는 파서를 던지고 있습니다. 따옴표가 너무 많습니다. >.

  parser.HasFieldsEnclosedInQuotes = true; 
      parser.SetDelimiters(","); 
      parser.TextFieldType = FieldType.Delimited; 

오류가

MalformedLineException: Line 9871 cannot be parsed using the current delimiters.

내가 계정에 어떻게 든 데이터를 문질러 싶습니다이다 : 나는이 설정으로 Microsoft.VisualBasic.FileIO 네임 스페이스에 TextFieldParser를 사용하고 <

이것을 위해 어떻게해야할지 모르겠다. 아니면이 줄을 건너 뛰는 방법이 있을까요? 내 상위 버전이 우리가 필요로하는 데이터를 건너 뛰는 것을 승인하지 않을 것이라고 생각하지만.

+0

문제 인용 부호를 이스케이프 처리해 보셨습니까? – itsme86

+0

@ itsme86 어떤 식으로 그들을 이스케이프합니까? –

+2

잘못된 줄을 건너 뛰고 정기적으로 수동으로 수정하여 다시 실행하는 파일에 기록하십시오.다행스럽게도 지루한 라인이 너무 많지는 않을 것입니다. – Kevin

답변

2

을 당신의 CSV에 부유 " 마크를 제거하기 위해, 당신이 그들을 찾으려면 다음 정규식을 사용 '

String sourcestring = "source string to match with pattern"; 
String matchpattern = @"(?<!^|,)""(?!(,|$))"; 
String replacementpattern = @"$1'"; 
Console.WriteLine(Regex.Replace(sourcestring,matchpattern,replacementpattern,RegexOptions.Multiline)); 

설명으로 대체 할 수 있습니다

@"(?<!^|,)""(?!(,|$))";은 문자열의 시작 선행되지 않은 ", 또는 ,를 찾을 발견하고 그것이 내가 한 번 aswell이 작업을 수행했던 문자열의 끝 또는 ,

+0

고마워, 이건 내가 필요한거야. –

1

나는

첫 번째 단계는 string.split(',')

다음 단계는 함께 속한 세그먼트를 결합하는 것입니다 사용하여 데이터를 분석하는 것입니다 전에이 일을 했어. 나는 본질적으로 무슨 짓을

  • 이 문자열은 따옴표로 시작하는 경우
  • 결합 된 문자열을 나타내는 새로운 목록을 만들 그것이로 시작하지 않는 경우 새 목록
  • 에 밀어 넣습니다 인용, 목록의 마지막 문자열로
  • 보너스를 추가 : 문자열은 따옴표로 끝나는하지만 다음 하나는 견적
로 시작하지 않는 경우에 예외를 발생

실제로 데이터에 나타날 수있는 것에 관한 규칙이 무엇인지에 따라 코드를 변경해야합니다.

1

CSV's file format의 코어에서 각 행은 하나의 행이며 해당 행의 각 셀은 쉼표로 구분됩니다. 귀하의 경우 귀하의 형식에는 괄호 안의 쉼표가 구분 기호로 간주되지 않고 대신 데이터의 일부인 (매우 불행한) 규정이 포함되어 있습니다. 잘못 놓인 따옴표가 줄의 나머지 부분에 영향을주고 표준 ASCII의 인용 부호는 열기와 닫기를 구별하지 못하기 때문에 원래의 의도를 모른 채로 복구 할 수있는 방법이 없습니다.

당신이 원래 의도 (데이터를 제공하는 사람을) 알고 않는 사람이 파일을 볼 수있는 방법으로 메시지를 기록하고 오류 정정 할 때입니다 :

if (parse_line(line, &data)) { 
    // save the data 
} else { 
    // log the error 
    fprintf(&stderr, "Bad line: %s", line); 
} 

을 그리고 따옴표가 이스케이프 개행 문자가 아니기 때문에이 오류가 발생한 후 다음 줄을 계속 사용할 수 있습니다.

추가 : 그리고 회사에서 선택할 수있는 경우 (즉, 회사 도구에서 데이터를 일련 번호로 지정하는 경우) CSV를 사용하지 마십시오. 훨씬 더 명확하게 정의 된 구문 분석 메커니즘을 사용하여 XML 또는 JSON과 같은 것을 사용하십시오.

2

저는 TextFieldParser에 익숙하지 않습니다. 그러나 CsvHelper과 함께, 당신은 잘못된 데이터에 대한 사용자 지정 처리기를 추가 할 수 있습니다

var config = new CsvConfiguration(); 
config.IgnoreReadingExceptions = true; 
config.ReadingExceptionCallback += (e, row) => 
{ 
    // you can add some custom patching here if possible 
    // or, save the line numbers and add/edit them manually later. 
}; 

using(var file = File.OpenRead(".csv")) 
using(var reader = new CsvReader(reader, config)) 
{ 
    reader.GetRecords<YourDtoClass>(); 
} 
1

(우리 모두가 거기했기 때문에) 모든 사람이 무슨 말을 내에서만 추가가 발생할 각각의 새로운 문제를 해결하려고 시도하는 것입니다 코드. 괜찮은 REGEX 문자열이 있습니다. https://www.google.com/?ion=1&espv=2#q=c-sharp+regex+csv+clean 또는 String.Replace ("\"\ "\" "," ")를 사용하여 수동으로 문제를 해결할 수 있습니다. ("\",, ","\ ",") 등). 결과적으로 실수를 많이 발견하고 수정하는 방법을 발견하면 수동 복구 속도가 크게 줄어들 것입니다. 대부분의 불량 데이터는 비슷한 실수로 인한 것일 수 있습니다. 건배!

PS - 아이디어 - 틱 (오랜만이야 - 내가 메모리에서 쓰고 같은 논리는 일부 조정을 neeed 수),하지만 당신은 요점 얻을 것이다 : 당신은 단지하려는 경우

public string[] parseCSVWithQuotes(string csvLine,int expectedNumberOfDataPoints) 
    { 
     string ret = ""; 
     string thisChar = ""; 
     string lastChar = ""; 
     bool needleDown = true; 
     for(int i = 0; i < csvLine.Length; i++) 
     { 
      thisChar = csvLine.Substring(i, 1); 
      if (thisChar == "'"&&lastChar!="'") 
       needleDown = needleDown == true ? false : true;//when needleDown = true, characters are treated literally 
      if (thisChar == ","&&lastChar!=",") { 
       if (needleDown) 
       { 
        ret += "|";//convert literal comma to pipe so it doesn't cause another break on split 
       }else 
       { 
        ret += ",";//break on split is intended because the comma is outside the single quote 
       } 
      } 
      if (!needleDown && (thisChar == "\"" || thisChar == "*")) {//repeat for any undesired character or use RegEx 
                     //do not add -- this eliminates any undesired characters outside single quotes 
      } 
      else 
      { 
       if ((lastChar == "'" || lastChar == "\"" || lastChar == ",") && thisChar == lastChar) 
       { 
        //do not add - this eliminates double characters 
       }else 
       { 
        ret += thisChar; 
        lastChar = thisChar; 
        //this character is not an undesired character, is no a double, is valid. 
       } 
      } 
     } 
     //we've cleaned as best we can 
     string[] parts = ret.Split(','); 
     if(parts.Length==expectedNumberOfDataPoints){ 
     for(int i = 0; i < parts.Length; i++) 
     { 
      //go back and replace the temporary pipe with the literal comma AFTER split 
      parts[i] = parts[i].Replace("|", ","); 
     } 

     return parts; 
     }else{ 
      //save ret to bad CSV log 
      return null; 
     } 
    } 
+0

CSV 구문 분석을 처리하는 데 사용 된 샘플을 추가했습니다 (메모리에서 회수 한 것만 큼). 한 번에 한 캐릭터를 통과하기 때문에 다소 짜증나지만, 당신이 좋은 RegExer라면 훨씬 더 좋은 일을 성취 할 수있을 것입니다. 그것은 꽤 있을지도 모르지만 그것 (또는 그것과 같은 무엇인가)은 나를 위해 일했다. 행운을 빕니다! –

0

다음되지 않습니다. 내 접근 방식은 선을 통해 나가 읽고 있던 것을 추적하는 것이 었습니다. 기본적으로, 내 잘못 된 .csv 데이터를 완전히 제어 할 수있는 입력 라인에서 토큰을 잘라 내 자신의 스캐너를 코딩했습니다.

For each character on a line of input. 
1. when outside of a string meeting a comma => all of the previous string (which can be empty) is a valid token. 
2. when outside of a sting meeting anything but a comma or a quote => now you have a real problem, unquoted tekst => handle as you see fit. 
3. when outside of a string meeing a quote => found a start of string. 
4. when inside of a string meeting a comma => accept the comma as part of the string. 
5. when inside of the string meeting a qoute => trouble starts here, mark this point. 
    6. continue and when meeting a comma (skipping white space if desired) close the string, 'unread' the comma and continue. (than will bring you to point 1.) 
    7. or continue and when meeting a quote -> obviously, what was read must be part of the string, add it to the string, 'unread' the quote and continue. (that will you bring to point 5) 
    8. or continue and find an whitespace, then End Of Line ('\n') -> the last qoute must be the closing quote. accept the string as a value. 
    9. or continue and fine non-whitespace, then End Of Line. -> now you have a real problem, you have the start of a string but it is not closed -> handle the error as you see fit. 

.csv 파일의 필드의 수는 당신이 필드 seperators로 인식하고 라인의 끝을 볼 때 당신이 당신을 알고 쉼표의 셀 수 고정되어있는 경우 :

내가 무슨 짓을 또 다른 문제가 있는지 여부.

입력 줄에서받은 문자열 스트림을 사용하면 '깨끗한'.csv 줄을 만들 수 있습니다. 이렇게하면 이미 존재하는 코드에서 사용할 수있는 받아 들인 깨끗한 입력 버퍼를 만들 수 있습니다.

관련 문제