2010-07-03 35 views
9

Tôi phải phân tích cú pháp một số bảng từ tệp văn bản ASCII. Đây là một phần mẫu:Regex: Các nhóm chụp lặp lại

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 

Bảng bao gồm 1 cột văn bản và 8 cột số dấu phẩy động. Tôi muốn nắm bắt từng cột thông qua regex.

Tôi khá mới đối với cụm từ thông dụng. Đây là mẫu regex bị lỗi mà tôi đưa ra:

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

Nhưng mẫu chỉ ghi lại cột đầu tiên và cột cuối cùng. RegexBuddy cũng phát ra cảnh báo sau:

Bạn lặp lại nhóm chụp . Nhóm sẽ chỉ chụp lần lặp cuối cùng. Đặt nhóm chụp xung quanh nhóm được lặp lại thành chụp tất cả các lần lặp lại.

Tôi đã tham khảo tệp trợ giúp của họ, nhưng tôi không có đầu mối về cách giải quyết vấn đề này.

Làm cách nào để tôi có thể chụp từng cột một cách riêng biệt?

+0

Bạn đang sử dụng ngôn ngữ nào? Trong .NET thật dễ dàng. –

+0

@Tim: Có, tôi có ý định viết chương trình bằng C#. Nhưng hiện tại, tôi đang tạo mẫu bằng Python. – invarbrass

+0

Xem thêm: http: // stackoverflow.com/questions/3029127/is-there-a-regex-hương vị-đó-cho phép-tôi-to-count-the-số-of-repetitions-phù hợp/ – polygenelubricants

Trả lời

12

Trong C# (sửa đổi từ this example):

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++; 
     } 
    } 
} 

Output:

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

Cảm ơn bạn đã đứng lên. Tôi đang xem xét thuộc tính Group.Captures. – invarbrass

+2

'Captures' là một tính năng gọn gàng, nhưng có vẻ như quá mức cần thiết ở đây. Tại sao không chỉ tách từng dòng trên khoảng trắng? Ngay cả khi bạn sử dụng regex để xác nhận định dạng của dòng, nó vẫn còn ít công việc. –

5

Thật không may bạn cần phải lặp lại (…) 8 lần để nhận riêng từng cột.

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

Nếu mã là có thể, trước tiên bạn có thể phù hợp với những cột số như một toàn thể

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

sau đó tách các cột bằng dấu cách

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

Kenny, cảm ơn phản hồi nhanh chóng! Tôi thực sự đang sử dụng mẫu đó ngay bây giờ. Nhưng tôi đã tự hỏi nếu có một giải pháp tốt hơn bằng cách sử dụng lặp lại nhóm chụp. – invarbrass

+0

@invarbrass: Không phải với các nhóm chụp lặp đi lặp lại mà tôi biết. Regexes thường làm việc tốt nhất nếu bạn không cố gắng để lạm dụng chúng với một shot. –

+0

KennyTM: Cảm ơn! Giải pháp của bạn hoạt động - Tôi đã làm một cái gì đó tương tự, mặc dù rất ít thanh lịch hơn. – invarbrass

4

Nếu bạn muốn biết những gì các cảnh báo được xuất hiện cho, đó là vì nhóm chụp của bạn phù hợp với nhiều lần (8, như bạn nào đó) nhưng biến chụp chỉ có thể có một giá trị. Nó được gán giá trị cuối cùng phù hợp.

Như được mô tả trong question 1313332, việc truy xuất nhiều kết quả trùng khớp này thường không thể thực hiện với biểu thức chính quy, mặc dù .NET và Perl 6 có một số hỗ trợ cho nó.

Cảnh báo gợi ý rằng bạn có thể đặt một nhóm khác xung quanh toàn bộ, như thế này:

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

Sau đó bạn sẽ có thể xem tất cả các cột, nhưng tất nhiên họ sẽ không được tách ra. Vì thường không thể chụp chúng một cách riêng biệt, ý định phổ biến hơn là chụp tất cả và cảnh báo sẽ nhắc bạn về điều này.

Các vấn đề liên quan