2015-02-25 5 views
16

Обе из них, насколько я знаю, должны быть такими же, но я действительно вижу разницу, посмотрите на этот минимальный пример из this question:разница между [0-9] n раз и [0-9] {n} в R regexp

a<-c("/Cajon_Criolla_20141024","/Linon_20141115_20141130", 
"/Cat/LIQUID", 
"/c_puertas_20141206_20141107", 
"/C_Puertas_3_20141017_20141018", 
"/c_puertas_navidad_20141204_20141205") 

sub("(.*?)_([0-9]{8})(.*)$","\\2",a) 
[1] "20141024" "20141130" "/Cat/LIQUID" "20141107" "20141018" 
[6] "20141205" 

sub("(.*?)_([0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9])(.*)$","\\2",a) 
[1] "20141024" "20141115" "/Cat/LIQUID" "20141206" "20141017" 
[6] "20141204" 

Что мне не хватает? Или это ошибка?

+0

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

+2

Интересно, если вы измените круглые скобки на '' (. *)? _ ([0-9] [0-9] [0-9] [0-9] [0-9] [0-9] [0 -9] [0-9]). * $ "' Он работает –

+1

@RichardScriven, но это меняет смысл регулярного выражения, см .: 'sub (" (. *)? "," "," ___X ", perl = T) 'VS' sub ("(. *?)", "", "___x", perl = T) '. В этом случае это не имеет значения. – BrodieG

ответ

12

Это ошибка в библиотеке TRE, связанных с жадными модификаторов и групп захвата. См:

+0

Первый квантификатор, используемый в шаблоне, не является жадным, а модификатор жадного/неровного переключателя не используется, не уверен, что это та же ошибка. –

+0

@CasimiretHippolyte, конечно же, это не та же ошибка, но в группе захвата '(. *?)' Есть жадный модификатор '(. *?)', И в соответствии с экспериментом Ричарда, изменяя это на '(. *)?' (Т.е. жадный модификатор из группы захвата) исправляет его, поэтому кажется, что это та же проблема или, как минимум, очень тесно связана. – BrodieG

+0

'. *?' - не-жадный квантификатор. '. *' - жадный квантификатор. '(? U)' - это модификатор, который инвертирует эти значения. –

4

Настройка perl=TRUE дает тот же ответ (как и ожидалось) для обоих выражений:

> sub("(.*?)_([0-9]{8})(.*)$","\\2",a,perl=TRUE) 
[1] "20141024" "20141115" "/Cat/LIQUID" "20141206" "20141017" "20141204" 
> sub("(.*?)_([0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9])(.*)$","\\2",a,perl=TRUE) 
[1] "20141024" "20141115" "/Cat/LIQUID" "20141206" "20141017" "20141204" 
+4

Интересно, но это не объясняет разные результаты с режимом регулярного выражения по умолчанию. –

+0

Итак, вы говорите, что я должен заполнить отчет об ошибке? – cmbarbu

1

Хотя я был сначала убежден в ответе БродиГ, кажется, что [0-9] n раз и [0-9] {n} действительно отличаются друг от друга, по крайней мере, для двигателя «tre» regexp. Согласно http://www.regular-expressions.info {} оператор жадный, [0-9] нет.

Поэтому правое регулярное выражение в моем случае должен быть:

sub("(.*?)_([0-9]{8}?)(.*)$","\\2",a) 

внесение всех различий:

sub("(.*?)_([0-9]{8})(.*)$","\\2",a) 
    [1] "20141024" "20141130" "/Cat/LIQUID" "20141107" "20141018" 
    [6] "20141205" 
    sub("(.*?)_([0-9]{8}?)(.*)$","\\2",a) 
    [1] "20141024" "20141115" "/Cat/LIQUID" "20141206" "20141017" 
    [6] "20141204" 

И даже

> sub("(.*)_([0-9]{8}?)(.*)$","\\2",a) 
    [1] "20141024" "20141115" "/Cat/LIQUID" "20141206" "20141017" 
    [6] "20141204" 

Интерпретации: 1) Тр считает? как «оценить следующий атом в первый раз, когда вы сможете совместить этот атом». Это всегда верно для ". ?" как и все, и переключается на _ [0-9] {8}. При достижении первой группы из 6 чисел, если {} не является жадным (нет?), Так как (.) соответствует также первым 8 числам, поиск продолжает видеть, существует ли другое появление «_ [0-9] { 8} "можно найти на линии. Если он соответствует второму набору из 8 цифр, он также запоминает его как соответствующий шаблон, затем он достигает конца строки, последний совпадающий шаблон сохраняется, а [0-9] {8} сопоставляется со вторым набором из 8 номера.

2) Когда {} оператор модифицирован? Поиск останавливается при первом просмотре 8 чисел, проверьте, можно ли сопоставить _ (. *) С остальными. Он может, поэтому он возвращает первый набор из 8 чисел.

Обратите внимание, что Perl регулярное выражение двигатель работает по-другому,

1)? после {} ничего не меняет:

 sub("(.*)_([0-9]{8})","\\2",a,perl=TRUE) 
    [1] "20141024" "20141130" "/Cat/LIQUID" "20141107" "20141018" 
    [6] "20141205" 
    sub("(.*)_([0-9]{8}?)","\\2",a,perl=TRUE) 
    [1] "20141024" "20141130" "/Cat/LIQUID" "20141107" "20141018" 
    [6] "20141205" 

2) the? . Приложенные к * делает его остановиться на первый наборе 8 цифр:

 sub("(.*?)_([0-9]{8}).*","\\2",a,perl=TRUE) 
    [1] "20141024" "20141115" "/Cat/LIQUID" "20141206" "20141017" 
    [6] "20141204" 
    sub("(.*)_([0-9]{8}).*","\\2",a,perl=TRUE) 
    [1] "20141024" "20141130" "/Cat/LIQUID" "20141107" "20141018" 
    [6] "20141205" 

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

+3

Я уверен, что жадность '{' имеет смысл только при использовании форм дикой карты (например, '{1,8}'). Что может случиться здесь, так это то, что присутствие двух модификаторов жадности в группах захвата компенсирует ошибку в библиотеке TRE. – BrodieG

+0

Никогда не обращайте внимания на то, что жадность бессмысленна для шаблона с фиксированной шириной, такого как '{8}' (хотя это проблема здесь), ключевой проблемой является жадность самого левого шаблона. Регулярные выражения сопоставляются слева направо, поэтому жадность правильного шаблона не должна влиять на жадность левого, так как это соответствует первому. Но это происходит. Причина, по которой PERL и TRE различны, состоит в том, что в библиотеке TRE есть ошибка. – BrodieG

Смежные вопросы