2010-07-03 9 views
9

ASCII 텍스트 파일의 일부 테이블을 구문 분석해야합니다. 다음은 부분적인 샘플입니다.Regex : 반복되는 캡처 그룹

QSMDRYCELL 11.00 11.10 11.00 11.00 -.90  11  11000  1.212 
RECKITTBEN 192.50 209.00 192.50 201.80 5.21  34  2850  5.707 
RUPALIINS 150.00 159.00 150.00 156.25 6.29  4  80  .125 
SALAMCRST 164.00 164.75 163.00 163.25 -.45  80  8250 13.505 
SINGERBD 779.75 779.75 770.00 773.00 -.89  8  95  .735 
SONARBAINS 68.00 69.00 67.50 68.00  .74  11  3050  2.077 

표는 1 열의 텍스트와 8 열의 부동 소수점으로 구성됩니다. 정규 표현식을 통해 각 열을 캡처하고 싶습니다.

저는 정규식을 처음 접했습니다. 다음은 내가 잘못 생각한 정규식 패턴입니다 :

(\S+)\s+(\s+[\d\.\-]+){8} 

그러나 패턴은 첫 번째와 마지막 열만 캡처합니다. 또한 RegexBuddy는 다음과 같은 경고를 내 보냅니다.

캡쳐 그룹 을 반복했습니다. 그룹은 마지막 반복 만 을 캡처합니다. 반복 그룹 주위에 캡처 그룹을 넣어 모든 반복을 캡처하십시오.

나는 그들의 도움 파일을 참조했지만,이 문제를 해결하는 방법에 대한 단서가 없습니다.

어떻게 각 열을 개별적으로 캡처 할 수 있습니까?

+0

어떤 언어를 사용하고 있습니까? .NET에서는 쉽습니다. –

+0

@Tim : 예 C#으로 프로그램을 작성하려고합니다. 하지만 지금은 파이썬으로 프로토 타이핑을하고 있습니다. – invarbrass

+0

참고 : http : // stackoverflow.co.kr/questions/3029127/is-there-a-regex-flavor - 반복 횟수 일치 횟수/ – polygenelubricants

답변

12

에 의해 열을 분할 :

string input = "QSMDRYCELL 11.00 11.10 11.00 11.00 -.90  11  11000  1.212"; 
string pattern = @"^(\S+)\s+(\s+[\d.-]+){8}$"; 
Match match = Regex.Match(input, pattern, RegexOptions.MultiLine); 
if (match.Success) { 
    Console.WriteLine("Matched text: {0}", match.Value); 
    for (int ctr = 1; ctr < match.Groups.Count; ctr++) { 
     Console.WriteLine(" Group {0}: {1}", ctr, match.Groups[ctr].Value); 
     int captureCtr = 0; 
     foreach (Capture capture in match.Groups[ctr].Captures) { 
     Console.WriteLine("  Capture {0}: {1}", 
          captureCtr, capture.Value); 
     captureCtr++; 
     } 
    } 
} 

출력 : 캡처 그룹 (사용자가 지정한대로, 8) 여러 번 일치하지만 캡처 변수가 하나 개의 값을 가질 수 있기 때문에

Matched text: QSMDRYCELL 11.00 11.10 11.00 11.00 -.90  11  11000  1.212 
... 
    Group 2:  1.212 
     Capture 0: 11.00 
     Capture 1: 11.10 
     Capture 2: 11.00 
...etc. 
+0

감사합니다. 위로 머리. 나는 Group.Captures 속성을 조사하고있다. – invarbrass

+2

'Captures'는 깔끔한 기능이지만 지나치게 잔인합니다. 왜 공백에 각 줄을 나누지 않을까요? 라인 형식을 검증하기 위해 정규 표현식을 사용한다고 할지라도 여전히 효과가 없습니다. –

5

각 열을 별도로 가져 오려면 불행히도 (…)을 8 번 반복해야합니다. 코드가 가능한 경우

^(\S+)\s+([-.\d]+)\s+([-.\d]+)\s+([-.\d]+)\s+([-.\d]+)\s+([-.\d]+)\s+([-.\d]+)\s+([-.\d]+)\s+([-.\d]+)$ 

, 먼저 전체

>>> rx1 = re.compile(r'^(\S+)\s+((?:[-.\d]+\s+){7}[-.\d]+)$', re.M) 
>>> allres = rx1.findall(theAsciiText) 

으로 그 숫자 열을 일치시킬 수는 (this example에서 수정) C#에서 공간

>>> [[p] + q.split() for p, q in allres] 
+1

Kenny, 신속한 응답에 감사드립니다! 나는 실제로 그 패턴을 사용하고 있습니다. 그러나 반복 캡처 그룹을 사용하는 더 나은 솔루션이 있는지 궁금합니다. – invarbrass

+0

@invarbrass : 내가 알고있는 반복 캡처 그룹이 아닙니다. Regexes는 원 샷으로 과용하지 않으려 고 할 때 가장 잘 작동합니다. –

+0

KennyTM : 감사합니다! 당신의 솔루션은 작동합니다 - 나는 훨씬 덜 우아하지만 뭔가 비슷한 것을하고있었습니다. – invarbrass

4

당신이 경고가 표시되는 것을 알고 싶은 경우입니다. 일치 된 마지막 값이 지정됩니다.

question 1313332에 설명 된 것처럼 일반적으로 .NET 및 Perl 6이이를 지원하지만 정규 표현식에서는 이러한 여러 일치 항목을 검색 할 수 없습니다.

(\S+)\s+((\s+[\d\.\-]+){8}) 

당신은 모든 열을 볼 수있을 것입니다 만, 물론 그들은 분리 할 수없는 것 :

경고는이 같은 전체 세트 주위에 다른 그룹을 넣을 수 있다는 것을 의미한다. 일반적으로 개별적으로 캡처 할 수는 없기 때문에 모든 것을 캡처하는 것이 더 일반적이며, 경고는이 사실을 상기시키는 데 도움이됩니다.

관련 문제