извлечь слово с регулярным выражением

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

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

Почему?


person farka    schedule 07.06.2010    source источник
comment
Какой механизм регулярных выражений вы используете?   -  person Johnsyweb    schedule 07.06.2010
comment
Вам нужно принять ответ.   -  person 0x499602D2    schedule 29.09.2012


Ответы (4)


Ваше полное совпадение оценивается как '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'.

Каждый раз, когда вы хотите захватить что-либо, что соответствует определенному шаблону в определенной строке, всегда лучше использовать флаг global и назначать захваты в массив. Поскольку массив не является одним скаляром, таким как $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*))}, указав, что первый символ должен быть альфа, за которым следует любое количество символов слова. Тогда дамп выглядит так:

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

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

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

person Axeman    schedule 08.06.2010
comment
+1 Мне это кажется чертовски прекрасным объяснением - помимо служебного долга. - person Mike; 25.06.2010

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

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

(\w+)
person Konrad Rudolph    schedule 07.06.2010
comment
я использую регулярное выражение, я хочу только TempatoA и CelcieusB vor! - person farka; 07.06.2010
comment
@farka: Покажите нам, как вы используете это выражение. Неправильное не выражение, а то, как вы его используете. - person Konrad Rudolph; 07.06.2010
comment
я хочу извлечь только слова bevor! и между 1/словом1 2/словом2 3/словом21...n/словом - person farka; 07.06.2010

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

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

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

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

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

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

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

myregexp = pcre_compile("(?<=\\d/)\\w+(?=.*!)", 0, &error, &erroroffset, NULL);
person Tim Pietzcker    schedule 07.06.2010
comment
я использую регулярное выражение pcrl perl comapatibe - person farka; 08.06.2010
comment
На каком языке программирования? PCRE доступен для многих языков. Хорошей новостью является то, что регулярное выражение будет работать, поскольку PCRE поддерживает поиск. - person Tim Pietzcker; 08.06.2010
comment
Пожалуйста, ответьте на мой вопрос, иначе ничем не сможем вам помочь. - person Tim Pietzcker; 08.06.2010

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

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

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

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

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

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

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

person Robert Wohlfarth    schedule 08.06.2010