2011-12-08 22 views
5

Tôi sẽ đặt nó ở ngay đó: Tôi kinh khủng với các biểu thức chính quy. Tôi đã cố gắng đưa ra một giải pháp để giải quyết vấn đề của mình nhưng tôi thực sự không biết nhiều về chúng. . .Cụm từ thông dụng để khớp với các thứ nguyên đối tượng

Hãy tưởng tượng một số câu dọc theo dòng sau đây:

  • Xin chào blah blah. Đó là khoảng 11 1/2 "x 32".
  • Kích thước là 8 x 10-3/5!
  • Có lẽ ở đâu đó trong khu vực 22 "x 17".
  • Các cuộn là khá lớn: 42 1/2" ... X 60 yd
  • Họ đều là 5,76 8 khung
  • Ừ, có lẽ nó dài khoảng 84cm
  • tôi nghĩ về 13/19" .
  • Không, có thể là 86 cm.

Tôi muốn, càng sạch càng tốt, trích xuất các thứ nguyên mục từ trong các câu này. Trong một thế giới hoàn hảo biểu thức chính quy sẽ ra như sau:

  • 11 1/2" x 32"
  • 8 x 10-3/5
  • 22" x 17"
  • 42 1/2" x 60 yd
  • 5,76 8
  • 84cm
  • 13/19"
  • 86 cm

Tôi tưởng tượng một thế giới mà các quy tắc sau được áp dụng:

  • Sau đây là đơn vị hợp lệ: {cm, mm, yd, yards, ", ', feet}, mặc dù tôi muốn một giải pháp mà coi một bộ tùy tiện của các đơn vị chứ không phải là một rõ ràng giải pháp cho các đơn vị trên.
  • Thứ nguyên luôn được mô tả bằng số, có thể hoặc không thể có các đơn vị theo dõi nó và có thể có hoặc không có phần phân số hoặc thập phân. Việc tạo thành một phần phân đoạn trên chính nó là được cho phép, ví dụ: 4/5".
  • Các bộ phận phân đoạn luôn có một số / tách tử số/mẫu số, và người ta có thể giả định không có khoảng cách giữa các phần (mặc dù nếu ai đó tính đến điều đó thật tuyệt vời!).
  • Kích thước có thể là một chiều hoặc hai chiều, trong trường hợp đó, người ta có thể giả định những điều sau đây có thể chấp nhận được để tách hai thứ nguyên: {x, by}. Nếu thứ nguyên chỉ là một chiều, thì phải có các đơn vị từ tập hợp ở trên, tức là, 22 cm là OK, .333 không phải là, cũng không phải là 4.33 oz.

Để cho bạn thấy tôi vô dụng với biểu thức chính quy (và ít nhất là cho tôi thấy), tôi đã đạt được điều này. . .

[1-9]+[/ ][x1-9] 

Update (2)

Các bạn rất nhanh và hiệu quả! Tôi sẽ thêm một vài thêm trường hợp thử nghiệm chưa được bao phủ bởi các biểu thức thông thường bên dưới:

  • cuối cùng nhưng có một trường hợp thử nghiệm là 12 yd x.
  • Trường hợp thử nghiệm cuối cùng là 99 cm.
  • Câu này không có kích thước trong nó: 342/5553/222.
  • Ba thứ nguyên? 22 "x 17" x 12 cm
  • Đây là mã sản phẩm: c720 với số khác 83 x tốt hơn.
  • Một số riêng. 21.
  • Khối lượng không được khớp với 0,32 oz.

Những nên dẫn đến việc sau (# chỉ ra không có gì phải phù hợp):

  • 12 yd
  • 99 cm
  • #
  • 22" x 17" x 12 cm
  • #
  • #
  • #

Tôi đã thích nghi M42's câu trả lời dưới đây, để:

\d+(?:\.\d+)?[\s-]*(?:\d+)?(?:\/\d+)?(?:cm|mm|yd|"|'|feet)(?:\s*x\s*|\s*by\s*)?(?:\d+(?:\.\d+)?[\s*-]*(?:\d+(?:\/\d+)?)?(?:cm|mm|yd|"|'|feet)?)? 

Nhưng trong khi đó giải quyết một số trường hợp thử nghiệm mới nó bây giờ không phù hợp với những người khác sau.Nó báo cáo:

  • 11 1/2" x 32" PASS
  • (không có gì) FAIL
  • 22" x 17" PASS
  • 42 1/2" x 60 yd PASS
  • (không có gì) FAIL
  • 84cm PASS
  • 13/19" PASS
  • 86 cm PASS
  • 22" PASS
  • (không có gì) FAIL
  • (không có gì) FAIL

  • 12 yd x FAIL

  • 99 cm bởi FAIL
  • 22" x 17" [và cũng có thể, nhưng riêng '12 cm '] FAIL
  • PASS

  • PASS

+0

bạn coud vui lòng cung cấp các chuỗi đầu vào và ouput dự kiến ​​là bao nhiêu? – Toto

+0

Chắc chắn. Tôi đã cung cấp cho họ một định dạng dễ dàng hơn cho bạn ở đây: http://pastebin.com/txfJs8LX Cảm ơn rất nhiều! – Edwardr

Trả lời

5

Phiên bản mới, gần mục tiêu, 2 thất bại kiểm tra

#!/usr/local/bin/perl 
use Modern::Perl; 
use Test::More; 

my $re1 = qr/\d+(?:\.\d+)?[\s-]*(?:\d+)?(?:\/\d+)?(?:cm|mm|yd|"|'|feet)/; 
my $re2 = qr/(?:\s*x\s*|\s*by\s*)/; 
my $re3 = qr/\d+(?:\.\d+)?[\s-]*(?:\d+)?(?:\/\d+)?(?:cm|mm|yd|"|'|feet|frames)/; 
my @out = (
'11 1/2" x 32"', 
'8 x 10-3/5', 
'22" x 17"', 
'42 1/2" x 60 yd', 
'5.76 by 8 frames', 
'84cm', 
'13/19"', 
'86 cm', 
'12 yd', 
'99 cm', 
'no match', 
'22" x 17" x 12 cm', 
'no match', 
'no match', 
'no match', 
); 
my $i = 0; 
my $xx = '22" x 17"'; 
while(<DATA>) { 
    chomp; 
    if (/($re1(?:$re2$re3)?(?:$re2$re1)?)/) { 
     ok($1 eq $out[$i], $1 . ' in ' . $_); 
    } else { 
     ok($out[$i] eq 'no match', ' got "no match" in '.$_); 
    } 
    $i++; 
} 
done_testing; 


__DATA__ 
Hello blah blah. It's around 11 1/2" x 32". 
The dimensions are 8 x 10-3/5! 
Probably somewhere in the region of 22" x 17". 
The roll is quite large: 42 1/2" x 60 yd. 
They are all 5.76 by 8 frames. 
Yeah, maybe it's around 84cm long. 
I think about 13/19". 
No, it's probably 86 cm actually. 
The last but one test case is 12 yd x. 
The last test case is 99 cm by. 
This sentence doesn't have dimensions in it: 342/5553/222. 
Three dimensions? 22" x 17" x 12 cm 
This is a product code: c720 with another number 83 x better. 
A number on its own 21. 
A volume shouldn't match 0.332 oz. 

đầu ra:

# Failed test ' got "no match" in The dimensions are 8 x 10-3/5!' 
# at C:\tests\perl\test6.pl line 42. 
# Failed test ' got "no match" in They are all 5.76 by 8 frames.' 
# at C:\tests\perl\test6.pl line 42. 
# Looks like you failed 2 tests of 15. 
ok 1 - 11 1/2" x 32" in Hello blah blah. It's around 11 1/2" x 32". 
not ok 2 - got "no match" in The dimensions are 8 x 10-3/5! 
ok 3 - 22" x 17" in Probably somewhere in the region of 22" x 17". 
ok 4 - 42 1/2" x 60 yd in The roll is quite large: 42 1/2" x 60 yd. 
not ok 5 - got "no match" in They are all 5.76 by 8 frames. 
ok 6 - 84cm in Yeah, maybe it's around 84cm long. 
ok 7 - 13/19" in I think about 13/19". 
ok 8 - 86 cm in No, it's probably 86 cm actually. 
ok 9 - 12 yd in The last but one test case is 12 yd x. 
ok 10 - 99 cm in The last test case is 99 cm by. 
ok 11 - got "no match" in This sentence doesn't have dimensions in it: 342/5553/222. 
ok 12 - 22" x 17" x 12 cm in Three dimensions? 22" x 17" x 12 cm 
ok 13 - got "no match" in This is a product code: c720 with another number 83 x better. 
ok 14 - got "no match" in A number on its own 21. 
ok 15 - got "no match" in A volume shouldn't match 0.332 oz. 
1..15 

Có vẻ như khó khăn để phù hợp với 5.76 by 8 frames nhưng không 0.332 oz, đôi khi bạn phải khớp số với đơn vị và số không có đơn vị.

Tôi xin lỗi, tôi không thể làm tốt hơn.

+0

Điều này khớp với mọi thứ, bao gồm những thứ như 12 yd trước 23,3. Tuy nhiên, làm thế nào để cải thiện nó để tránh trường hợp sau đây? "12 yd x" hiện đang khớp với regex của bạn, nhưng tôi đoán là thích hợp hơn nếu trong trường hợp đó chỉ có 12 yd được khớp. Cảm ơn! – Edwardr

+0

Tôi đã cố gắng điều chỉnh câu trả lời của bạn cho một số trường hợp tổng quát hơn nhưng không thành công. . . Đã cập nhật câu hỏi cho phù hợp. – Edwardr

2

Một trong những giải pháp khả thi (nên NLP tương thích vì nó chỉ sử dụng cú pháp regex cơ bản):

foundMatch = Regex.IsMatch(SubjectString, @"\d+(?: |cm|\.|""|/)[\d/""x -]*(?:\b(?:by\s*\d+|cm|yd)\b)?"); 

sẽ nhận được kết quả của bạn :)

Giải thích:

" 
\d    # Match a single digit 0..9 
    +    # Between one and unlimited times, as many times as possible, giving back as needed (greedy) 
(?:   # Match the regular expression below 
        # Match either the regular expression below (attempting the next alternative only if this one fails) 
     \   # Match the character “ ” literally 
    |    # Or match regular expression number 2 below (attempting the next alternative only if this one fails) 
     cm   # Match the characters “cm” literally 
    |    # Or match regular expression number 3 below (attempting the next alternative only if this one fails) 
     \.   # Match the character “.” literally 
    |    # Or match regular expression number 4 below (attempting the next alternative only if this one fails) 
     ""   # Match the character “""” literally 
    |    # Or match regular expression number 5 below (the entire group fails if this one fails to match) 
    /   # Match the character “/” literally 
) 
[\d/""x -]  # Match a single character present in the list below 
        # A single digit 0..9 
        # One of the characters “/""x” 
        # The character “ ” 
        # The character “-” 
    *    # Between zero and unlimited times, as many times as possible, giving back as needed (greedy) 
(?:    # Match the regular expression below 
    \b    # Assert position at a word boundary 
    (?:   # Match the regular expression below 
        # Match either the regular expression below (attempting the next alternative only if this one fails) 
     by  # Match the characters “by” literally 
     \s  # Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.) 
      *  # Between zero and unlimited times, as many times as possible, giving back as needed (greedy) 
     \d  # Match a single digit 0..9 
      +  # Between one and unlimited times, as many times as possible, giving back as needed (greedy) 
     |   # Or match regular expression number 2 below (attempting the next alternative only if this one fails) 
     cm  # Match the characters “cm” literally 
     |   # Or match regular expression number 3 below (the entire group fails if this one fails to match) 
     yd  # Match the characters “yd” literally 
    ) 
    \b    # Assert position at a word boundary 
)?    # Between zero and one times, as many times as possible, giving back as needed (greedy) 
" 
+0

Ồ, cảm ơn! Nó không hoàn toàn phù hợp với tất cả các trường hợp tưởng tượng của tôi. Ví dụ, nó không phù hợp nếu kích thước đầu tiên kết thúc bằng mm, cm, yd vv. Tôi nghĩ rằng tôi có thể làm việc ra làm thế nào để thích ứng với nó mặc dù. :-) – Edwardr

+0

@Edwardr Tôi đã sử dụng các ví dụ của bạn, nhưng bạn có thể mở rộng nó, tôi đoán :) – FailedDev

1

Đây là tất cả những gì tôi có thể nhận được với một biểu thức chính quy trong 'Perl'. Hãy cố gắng thích nghi với nó để hương vị regex của bạn:

\d.*\d(?:\s+\S+|\S+) 

Giải thích:

\d  # One digit. 
.*  # Any number of characters. 
\d  # One digit. All joined means to find all content between first and last digit. 
\s+\S+ # A non-space characters after some space. It tries to match any unit like 'cm' or 'yd'. 
|   # Or. Select one of two expressions between parentheses. 
\S+  # Any number of non-space characters. It tries to match double-quotes, or units joined to the 
      # last number. 

thử nghiệm của tôi:

Nội dung kịch bản.pl:

use warnings; 
use strict; 

while (<DATA>) { 
     print qq[$1\n] if m/(\d.*\d(\s+\S+|\S+))/ 
} 

__DATA__ 
Hello blah blah. It's around 11 1/2" x 32". 
The dimensions are 8 x 10-3/5! 
Probably somewhere in the region of 22" x 17". 
The roll is quite large: 42 1/2" x 60 yd. 
They are all 5.76 by 8 frames. 
Yeah, maybe it's around 84cm long. 
I think about 13/19". 
No, it's probably 86 cm actually. 

Chạy kịch bản:

perl script.pl 

Kết quả:

11 1/2" x 32". 
8 x 10-3/5! 
22" x 17". 
42 1/2" x 60 yd. 
5.76 by 8 frames. 
84cm 
13/19". 
86 cm 
Các vấn đề liên quan