2011-12-08 14 views
5

Powiem to od razu: Jestem okropny w wyrażeniach regularnych. Próbowałem wymyślić taki, który rozwiązałby mój problem, ale naprawdę niewiele o nich wiem. . .Wyrażenie regularne pasujące do wymiarów obiektu

Wyobraźmy sobie kilka zdań wzdłuż następujących linii:

  • Witam bla bla. Ma około 11 1/2 "x 32".
  • Wymiary to 8 x 10-3/5!
  • Prawdopodobnie gdzieś w regionie 22 "x 17".
  • Rolka jest dość duży: 42 1/2" ... X 60 km
  • Wszystkie są 5.76 przez 8 klatek
  • Tak, może to jest około 84cm długości
  • myślę o 13/19" .
  • Nie, to prawdopodobnie 86 cm.

Chcę, tak czysto jak to możliwe, wydobyć wymiary przedmiotu z tych zdań. W idealnym świecie wyrażenie regularne że wyjście następuje:

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

sobie wyobrazić świat, w którym stosuje się następujące zasady:

  • ważne są następujące jednostki: {cm, mm, yd, yards, ", ', feet}, choć wolałbym rozwiązanie, które uzna za dowolny zbiór jednostek zamiast jawne rozwiązanie dla powyższych jednostek.
  • Wymiar jest zawsze opisywany numerycznie, może mieć lub nie może mieć jednostek za nim i może lub nie może mieć części ułamkowej lub dziesiętnej. Składanie części ułamkowej na własnej jest dozwolone, np. 4/5".
  • Części ułamkowe zawsze mają / oddzielając licznik/mianownik, i można założyć, że między częściami nie ma spacji (choć jeśli ktoś to weźmie pod uwagę, to świetnie!).
  • Wymiary mogą być jednowymiarowe lub dwuwymiarowe, w którym to przypadku można przyjąć, że akceptowalne są następujące dwa wymiary: {x, by}. Jeśli wymiar jest tylko jednowymiarowy, musi on mieć jednostki z powyższego zestawu, to jest 22 cm jest OK, .333 nie jest, ani nie jest 4.33 oz.

Aby pokazać, jak bezużyteczna jestem przy użyciu wyrażeń regularnych (i pokazać, że przynajmniej próbowałem!), Dotarłem tak daleko. . .

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

Aktualizacja (2)

Jesteście bardzo szybko i sprawnie! Mam zamiar dodać kilka dodatkowych przypadków testowych, które nie zostały objęte wyrażeń regularnych poniżej:

  • Przedostatni sprawdzian jest 12 km x.
  • Ostatni przypadek testowy wynosi 99 cm.
  • Zdanie to nie ma wymiarów: 342/5553/222.
  • Trzy wymiary? 22 "x 17" x 12 cm
  • To jest kod produktu: c720 o innym numerze 83 x lepiej.
  • Liczba sama w sobie 21.
  • Objętość nie powinna odpowiadać 0,332 oz.

Powinno to następujący (# oznacza nic powinna odpowiadać):

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

Mam dostosowany M42's odpowiedź poniżej, aby:

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

Ale podczas gdy rozwiązuje kilka nowych przypadków testowych, to teraz nie pasują następujące innych.przedstawia on:

  • 11 1/2" x 32" PASS
  • (nic) nie
  • 22" x 17" PASS
  • 42 1/2" x 60 km PASS
  • (nic) nie
  • 84cm PASS
  • 13/19" PASS
  • 86 cm PASS
  • 22" PASS
  • (nic) nie
  • (nic) nie

  • 12 YD x FAIL

  • 99 cm na FAIL
  • 22" x 17" [a także, ale oddzielnie '12 cm '] FAIL
  • PASS

  • PASS

+0

Coud Pan podać ciągi wejściowe i jaki jest spodziewany ouput? – Toto

+0

Pewnie. Dostarczyłem je w łatwiejszym formacie dla ciebie tutaj: http://pastebin.com/txfJs8LX Dziękuję bardzo! – Edwardr

Odpowiedz

5

Nowa wersja, w pobliżu tarczy, 2 nie powiodło się testy

#!/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. 

wyjściowa:

# 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 

Trudno dopasować 5.76 by 8 frames ale nie 0.332 oz, czasami trzeba dopasuj liczby do jednostki i liczby bez jednostki.

Przykro mi, nie jestem w stanie zrobić nic lepszego.

+0

Ten pasuje do wszystkiego, w tym do 12 jarda przez 23,3. Jak jednak można go ulepszyć, aby uniknąć następującego przypadku? "12 yd x" jest obecnie dopasowane do twojego wyrażenia regularnego, ale myślę, że jest to lepsze, jeśli w tym przypadku pasuje tylko 12 yd. Dzięki! – Edwardr

+0

Próbowałem dostosować twoją odpowiedź do bardziej ogólnych przypadków, ale się nie powiodło. . . Zaktualizowane pytanie odpowiednio. – Edwardr

2

Jednym z wielu możliwych rozwiązań (powinny być zgodne NLP, ponieważ używa tylko podstawową składnię regex):

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

dostanie swoje wyniki :)

Objaśnienie:

" 
\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

Wow, dzięki! Nie pasuje do wszystkich moich wyimaginowanych przypadków. Na przykład nie pasuje, jeśli pierwszy wymiar kończy się w mm, cm, yd itp. Myślę, że mogę się dowiedzieć, jak to zaadaptować. :-) – Edwardr

+0

@Edwardr Użyłem twoich przykładów, ale możesz je przedłużyć :) – FailedDev

1

To wszystko, co mogę uzyskać za pomocą wyrażenia regularnego w "Perl". Starają się dostosować go do regex smaku:

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

Objaśnienie:

\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. 

Moje testy:

Zawartość skrypt.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. 

Uruchamianie skryptu:

perl script.pl 

Wynik:

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 
Powiązane problemy