извлечь слово с регулярным выражением - PullRequest
1 голос
/ 07 июня 2010

У меня есть строка 1/temperatoA,2/CelcieusB!23/33/44,55/66/77, и я хотел бы извлечь слова temperatoA и CelcieusB.

У меня есть это регулярное выражение (\d+/(\w+),?)*!, но я получаю только совпадение 1/temperatoA,2/CelcieusB!

Почему?

Ответы [ 4 ]

8 голосов
/ 08 июня 2010

Ваше целое совпадение оценивается как '1/temperatoA,2/CelcieusB', поскольку оно соответствует следующему выражению:

qr{ (       # begin group 
      \d+   # at least one digit
      /     # followed by a slash
     (\w+)  # followed by at least one word characters
     ,?     # maybe a comma
    )*      # ANY number of repetitions of this pattern.
}x;

'1/temperatoA,' сначала выполняет захват # 1, но, поскольку вы просите движок захватить как можно больше из них, он возвращается и обнаруживает, что шаблон повторяется в '2/CelcieusB' (запятая не нужна). Итак, все совпадение - это то, что вы сказали, но то, что вы, вероятно, не ожидали, это то, что '2/CelcieusB' заменяет '1/temperatoA,' на $1, поэтому $1 читает '2/CelcieusB'.

Каждый раз, когда вы хотите захватить все, что соответствует определенному шаблону в определенной строке, всегда лучше использовать флаг g lobal и назначить захваты в массив. Поскольку массив не является одним скаляром, таким как $1, он может содержать все значения, которые были получены для захвата # 1.

Когда я делаю это:

my $str   = '1/temperatoA,2/CelcieusB!23/33/44,55/66/77';
my $regex = qr{(\d+/(\w+))};
if ( my @matches = $str =~ /$regex/g ) { 
    print Dumper( \@matches );
}

Я получаю это:

$VAR1 = [
          '1/temperatoA',
          'temperatoA',
          '2/CelcieusB',
          'CelcieusB',
          '23/33',
          '33',
          '55/66',
          '66'
        ];

Теперь, я думаю, это, вероятно, не то, что вы ожидали. Но '3' и '6' являются символами слова , и поэтому - после косой черты - они соответствуют выражению.

Итак, если это проблема, вы можете изменить свое регулярное выражение на эквивалентное: qr{(\d+/(\p{Alpha}\w*))}, указав, что первым символом должен быть alpha , за которым следует любое количество символов слова. Тогда свалка выглядит так:

$VAR1 = [
          '1/temperatoA',
          'temperatoA',
          '2/CelcieusB',
          'CelcieusB'
        ];

И если вы хотите только 'temperatoA' или 'CelcieusB', то вы захватываете больше, чем нужно, и вы хотите, чтобы ваше регулярное выражение было qr{\d+/(\p{Alpha}\w*)}.

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

1 голос
/ 08 июня 2010

С помощью Perl-совместимого движка регулярных выражений вы можете искать

(?<=\d/)\w+(?=.*!)

(?<=\d/) утверждает, что перед началом матча есть цифра и косая черта

\w+ соответствует идентификатору. Это позволяет для букв, цифр и подчеркивания. Если вы хотите разрешить только буквы, используйте [A-Za-z]+.

(?=.*!) утверждает, что в строке впереди ! - i. е. регулярное выражение потерпит неудачу, как только мы передадим !.

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

E. Например, для использования в C (с библиотекой PCRE) вам необходимо избежать обратной косой черты:

myregexp = pcre_compile("(?<=\\d/)\\w+(?=.*!)", 0, &error, &erroroffset, NULL);
1 голос
/ 07 июня 2010

Вопрос здесь: почему вы используете регулярное выражение, которое так явно неправильно? Как ты это получил?

Вы хотите получить следующее выражение:

(\w+)
0 голосов
/ 08 июня 2010

Будет ли это работать?

/([[:alpha:]]\w+)\b(?=.*!)

Я сделал следующие предположения ...

  1. A Слово начинается с буквенного символа.
  2. Слово всегда следует за косой чертой.Нет промежуточных пробелов, нет слов в середине.
  3. Слова после восклицательного знака игнорируются.
  4. У вас есть какая-то петля для захвата более одного слова.Я недостаточно знаком с библиотекой C. Чтобы привести пример.

[[:alpha:]] соответствует любому буквенному символу.

\b соответствует границе слова.

А (?=.*!) пришло от сообщения Тима Пицкера .

...