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

Я пытаюсь найти в строке один пробел, окруженный цифрой с каждой стороны. Я построил следующий пример:

library('stringr')
str1 <- "1805.6 1-1 1"
str_locate_all(str1, "\\s+")[[1]]
str_locate_all(str1, "[[:digit:]]\\s[[:digit:]]")[[1]]

Что возвращает:

str_locate_all(str1, "\\s+")[[1]]
     start end
[1,]     7   7
[2,]    11  11

str_locate_all(str1, "[[:digit:]]\\s[[:digit:]]")[[1]]
     start end
[1,]     6   8
[2,]    10  12

Что я и ожидал увидеть. Теперь сделайте то же самое с другой строкой:

str2 <- "1805.6 1 1 1"
str_locate_all(str2, "\\s+")[[1]]
str_locate_all(str2, "[[:digit:]]\\s[[:digit:]]")[[1]]

Но, похоже, отсутствует одно из пробелов, окруженных цифрами (обратите внимание, что второй шаблон возвращает только 2 записи):

str_locate_all(str2, "\\s+")[[1]]
     start end
[1,]     7   7
[2,]     9   9
[3,]    11  11

str_locate_all(str2, "[[:digit:]]\\s[[:digit:]]")[[1]]
     start end
[1,]     6   8
[2,]    10  12

Итак, вопрос в том, почему второй шаблон не видит средний пробел и не возвращает строку с 8 10 ? Я уверен, что просто не вижу вещей в мышлении regex.


person Bryan Hanson    schedule 24.05.2016    source источник


Ответы (1)


Ваша цифра после пробела расходуется после совпадения. Таким образом, вы не можете найти совпадение. В вашем примере

Примечание: - x обозначает совпадающие цифры

1805.6 1 1 1
     x^x
      |
   First match

1805.6 1 1 1
        ^
        |
Once the regex engine moves forward, it cannot see backward(unless lookbehind is used).
Here, first digit from regex is matched with space which is not correct so the match fails outright and next position is attempted.

1805.6 1 1 1    
         x^x
         ||Matches digit
         |Matches space
      Matches digit
     (Second match)

This goes on till end of string is reached

Визуализируйте здесь

введите здесь описание изображения

Вместо этого вы можете использовать lookahead как

> str_locate_all(str1, "\\d\\s(?=\\d)")[[1]]
     start end
[1,]     6   7
[2,]     8   9
[3,]    10  11

Так как lookaheads имеют нулевую ширину, мы получаем позицию на единицу меньше фактической конечной позиции.

person rock321987    schedule 24.05.2016
comment
Спасибо за это ясное объяснение. Связанный вопрос: есть ли функциональная разница между использованием [[:digit:]] и \\d? Спасибо. - person Bryan Hanson; 24.05.2016
comment
@BryanHanson нет, я так не думаю (насколько мне известно).. одна вещь, которую я заметил, это то, что [[:digit:]] поддерживается в основном движком DFA - person rock321987; 24.05.2016
comment
Спасибо. Это было в моей шпаргалке, поэтому я использовал ее. В будущем буду использовать более короткую форму. - person Bryan Hanson; 24.05.2016