Регулярное выражение для соответствия размерам объекта - PullRequest
7 голосов
/ 08 декабря 2011

Я прямо скажу: я ужасен с регулярными выражениями.Я пытался придумать один, чтобы решить мою проблему, но я действительно не знаю о них много.,.

Представьте себе несколько предложений в следующих строках:

  • Здравствуйте, бла-бла.Это примерно 11 1/2 "x 32".
  • Размеры 8 x 10-3 / 5!
  • Возможно где-то в районе 22 "x 17".
  • Рулон довольно большой: 42 1/2 "x 60 ярдов.
  • Они все 5,76 на 8 кадров.
  • Да, может быть, это около 84 см в длину.
  • Я думаю о 13/19 ".
  • Нет, на самом деле это, вероятно, 86 см.

Я хочу, насколько это возможно, просто извлечь размеры элементов из этихприговоры.В идеальном мире регулярное выражение будет выводить следующее:

  • 11 1/2 "x 32"
  • 8 x 10-3 / 5
  • 22 "x 17"
  • 42 1/2 "x 60 ярдов
  • 5,76 на 8
  • 84 см
  • 13/19"
  • 86 см

Я представляю мир, в котором применяются следующие правила:

  • Действительными являются следующие единицы: {cm, mm, yd, yards, ", ', feet}, хотя я бы предпочелрешение, которое рассматривает произвольный набор единиц, а не явное решение для вышеуказанных единиц.
  • Измерение всегда описывается численно, может иметь или не иметь следующие после него единицы измерения, а может иметь или не иметь дробное или десятичное числочасть.Допускается создание только дробной части, например, 4/5".
  • Дробные части всегда имеют /, разделяющий числитель / знаменатель, и можно предположить, что между частями нет пробела(хотя, если кто-то примет это во внимание, это здорово!).
  • Размеры могут быть одномерными или двухмерными, и в этом случае можно предположить, что для разделения двух измерений допустимо следующее: {x, by}.Если измерение является только одномерным, оно должно иметь единицы измерения из приведенного выше, то есть 22 cm в порядке, .333 нет и 4.33 oz.

Чтобы показать вам, насколько я бесполезен с регулярными выражениями (и показать, что я хотя бы попытался!), Я дошел до этого.,.

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

Обновление (2)

Вы, ребята, очень быстрые и эффективные!Я собираюсь добавить дополнительные несколько тестовых случаев, которые не были охвачены регулярными выражениями ниже:

  • Последний, но один тестовый случай - 12 ярдов x.
  • Последний тестовый пример - 99 см.
  • В этом предложении нет размеров: 342/5553 / 222.
  • Три измерения?22 "x 17" x 12 см
  • Это код продукта: c720 с другим номером 83 х лучше.
  • Число само по себе 21.
  • Объем не должен соответствовать 0,332 унции.

Это должно привести к следующему (# ничего не означаетдолжно совпадать):

  • 12 ярдов
  • 99 см
  • #
  • 22 "x 17" x 12 см
  • #
  • #
  • #

Я адаптировал M42's ответ ниже, чтобы:

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

Но хотя это разрешает некоторые новые тестовые случаи, теперь оно не соответствует следующим другим.Он сообщает:

  • 11 1/2 "x 32" PASS
  • (ничего) FAIL
  • 22 "x 17" PASS
  • 42 1/2 "x 60 м ПРОЙДЕН
  • (ничего) НЕУДАЧ *
  • 84 см ПРОЙДЕН
  • 13/19" ПРОЙДЕН
  • 86 см1138 *
  • 22 "PASS
  • (ничего) FAIL
  • (ничто) FAIL

  • 12 ярдов x FAIL

  • 99 см по FAIL
  • 22 "x 17" [а также, но отдельно '12 см'] FAIL
  • PASS

  • PASS

Ответы [ 3 ]

5 голосов
/ 08 декабря 2011

Новая версия, рядом с целью, 2 неудачных теста

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

вывод:

#   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

Кажется, трудно сопоставить 5.76 by 8 frames, но не 0.332 oz, иногда нужно сопоставлять числа с единицей и числами без единицы.

Извините, я не могу добиться большего успеха.

2 голосов
/ 08 декабря 2011

Это все, что я могу получить с помощью регулярного выражения в Perl.Попробуйте адаптировать его к своему вкусу регулярных выражений:

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

Объяснение:

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

Мой тест:

Содержимое script.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.

Запуск сценария:

perl script.pl

Результат:

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
2 голосов
/ 08 декабря 2011

Одно из многих возможных решений (должно быть совместимо с nlp, поскольку оно использует только базовый синтаксис регулярных выражений):

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

Получит ваши результаты:)

Объяснение:

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