Регулярное выражение для сопоставления неаккуратных дробей / смешанных чисел - PullRequest
13 голосов
/ 29 октября 2008

У меня есть серия текста, которая содержит смешанные числа (то есть: целую часть и дробную часть). Проблема в том, что текст полон небрежного кода:

  1. Вся часть может существовать или не существовать (например, "10")
  2. Дробная часть может существовать или не существовать (например, «1/3»)
  3. Обе части могут быть разделены пробелами и / или дефисами (например: «10 1/3», «10-1 / 3», «10 - 1/3»).
  4. Сама дробь может иметь или не иметь пробелов между числом и косой чертой (например: «1/3», «1/3», «1/3»).
  5. Может быть другой текст после дроби, который необходимо игнорировать

Мне нужно регулярное выражение, которое может проанализировать эти элементы, чтобы я мог создать правильное число из этого беспорядка.

Ответы [ 3 ]

11 голосов
/ 29 октября 2008

Вот регулярное выражение, которое будет обрабатывать все данные, которые я могу добавить к нему:

(\d++(?! */))? *-? *(?:(\d+) */ *(\d+))?.*$

Эти цифры будут разбиты на следующие группы:

  1. Целая часть смешанного числа, если оно существует
  2. Числитель, если дробь выходит
  3. Знаменатель, если существует дробь

Также вот объяснение RegexBuddy для элементов (которое мне очень помогло при его создании):

Match the regular expression below and capture its match into backreference number 1 «(\d++(?! */))?»
   Between zero and one times, as many times as possible, giving back as needed (greedy) «?»
   Match a single digit 0..9 «\d++»
      Between one and unlimited times, as many times as possible, without giving back (possessive) «++»
   Assert that it is impossible to match the regex below starting at this position (negative lookahead) «(?! */)»
      Match the character “ ” literally « *»
         Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
      Match the character “/” literally «/»
Match the character “ ” literally « *»
   Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
Match the character “-” literally «-?»
   Between zero and one times, as many times as possible, giving back as needed (greedy) «?»
Match the character “ ” literally « *»
   Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
Match the regular expression below «(?:(\d+) */ *(\d+))?»
   Between zero and one times, as many times as possible, giving back as needed (greedy) «?»
   Match the regular expression below and capture its match into backreference number 2 «(\d+)»
      Match a single digit 0..9 «\d+»
         Between one and unlimited times, as many times as possible, giving back as needed (greedy) «+»
   Match the character “ ” literally « *»
      Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
   Match the character “/” literally «/»
   Match the character “ ” literally « *»
      Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
   Match the regular expression below and capture its match into backreference number 3 «(\d+)»
      Match a single digit 0..9 «\d+»
         Between one and unlimited times, as many times as possible, giving back as needed (greedy) «+»
Match any single character that is not a line break character «.*»
   Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
Assert position at the end of the string (or before the line break at the end of the string, if any) «$»
2 голосов
/ 29 октября 2008

Я думаю, что может быть проще решать различные случаи (полностью смешанные, только дроби, только числа) отдельно друг от друга. Например:

sub parse_mixed {
  my($mixed) = @_;

  if($mixed =~ /^ *(\d+)[- ]+(\d+) *\/ *(\d)+(\D.*)?$/) {
    return $1+$2/$3;
  } elsif($mixed =~ /^ *(\d+) *\/ *(\d+)(\D.*)?$/) {
    return $1/$2;
  } elsif($mixed =~ /^ *(\d+)(\D.*)?$/) {
    return $1;
  }
}

print parse_mixed("10"), "\n";
print parse_mixed("1/3"), "\n";
print parse_mixed("1 / 3"), "\n";
print parse_mixed("10 1/3"), "\n";
print parse_mixed("10-1/3"), "\n";
print parse_mixed("10 - 1/3"), "\n";
1 голос
/ 30 октября 2008

Если вы используете Perl 5.10, я бы так написал.

m{
  ^
  \s*       # skip leading spaces

  (?'whole'
   \d++
   (?! \s*[\/] )   # there should not be a slash immediately following a whole number
  )

  \s*

  (?:    # the rest should fail or succeed as a group

    -?        # ignore possible neg sign
    \s*

    (?'numerator'
     \d+
    )

    \s*
    [\/]
    \s*

    (?'denominator'
     \d+
    )
  )?
}x

Затем вы можете получить доступ к значениям из переменной %+ следующим образом:

$+{whole};
$+{numerator};
$+{denominator};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...