На прошлом семинаре мы разбирали функции из пакета stringr
. Однако, внутри R есть встроенные функции, которые работают похожим образом. Сегодня мы будем использовать их, а также познакомимся с регулярными выражениями.
Хотим:
grep(..., value=FALSE)
, stringr::str_detect()
grep(..., value=TRUE)
, stringr::str_extract()
, stringr::str_extract_all()
regexpr()
, gregexpr()
, stringr::str_locate()
, string::str_locate_all()
regmatches()
sub()
, gsub()
, stringr::str_replace()
, stringr::str_replace_all()
strsplit()
, stringr::str_split()
Регулярные выражения - это специальный язык, которые позволяет общаться со строками. Он содержит очень много специальных символов (кванторов), с помощью которых и происходит общение. Так как в основном все данные приходят из интернета в виде текста (будь то отзывы покупателей, сообщения ваших друзей вконтакте или просто текст из тегов при скраппинге страниц), уметь общаться с текстом очень важно, поэтому каждому аналитику данных нужно выучить этот язык. Ниже представлена небольшая таблица с наиболее часто используемыми кванторами в регулярных выражениях:
Символ | Описание |
---|---|
. |
один любой символ, кроме новой строки |
? |
0 или 1 вхождение шаблона слева |
+ |
1 и более вхождений шаблона слева |
* |
0 и более вхождений шаблона слева |
\w |
любая цифра или буква |
\W |
всё, кроме цифры или буквы |
\d |
любая цифра |
\D |
всё, кроме цифры |
\s |
любой пробельный символ |
\S |
любой непроблеьный символ |
\b |
граница слова |
[..] |
Один из символов в скобках |
[^..] |
Любой символ, кроме тех что в скобках |
\ |
Экранирование специальных символов (точки плюсы и тп) |
^ ; $ |
Начало и конец строки соответственно |
{n,m} |
От n до m вхождений |
{,m} |
От 0 до m вхождений |
a \| b |
a или b |
( ) |
Группирует выражение и возвращает найденный текст |
\t ; \n |
табуляция, новая строка |
Создадим глупую строку и посмотрим, как будут работать наши функции.
grep()
## [1] 1 3
Видим, что заглавные буквы и строчные функция различает. Если мы не хотим этого, то в аргумент ignore.case
нужно передать TRUE
## [1] 1 2 3
Если хотим не индексы, а сами значения, то в аргумент value
нужно передать TRUE
## [1] "I love apple and apple pie" "apple ipod"
Найдем каждую строку, начинающуюся с любого символа, за которым следует ‘pple’.
## [1] "Apple ipad" "apple ipod"
Строки, которые содержат p перед d и любой один символ между
## [1] "Apple ipad" "apple ipod"
Строки, которые содержат любую заглавную букву:
## [1] "I love apple and apple pie" "Apple ipad"
Строки, которые содержат любую заглавную или строчную букву
## [1] "I love apple and apple pie" "Apple ipad"
## [3] "apple ipod"
Строки, содержащие pad или pod:
## [1] "Apple ipad" "apple ipod"
regexpr()
и gregexpr()
Находим стартовые индексы нашего шаблона в строке. Если -1, значит совпадений не найдено.
## [1] 8 -1 1
## attr(,"match.length")
## [1] 5 -1 5
## attr(,"index.type")
## [1] "chars"
## attr(,"useBytes")
## [1] TRUE
gregexpr()
выдает тоже самое, но уже для каждого совпадения в каждой строке. Также теперь на выход идет list()
, а не массив!
## [[1]]
## [1] 8 18
## attr(,"match.length")
## [1] 5 5
## attr(,"index.type")
## [1] "chars"
## attr(,"useBytes")
## [1] TRUE
##
## [[2]]
## [1] -1
## attr(,"match.length")
## [1] -1
## attr(,"index.type")
## [1] "chars"
## attr(,"useBytes")
## [1] TRUE
##
## [[3]]
## [1] 1
## attr(,"match.length")
## [1] 5
## attr(,"index.type")
## [1] "chars"
## attr(,"useBytes")
## [1] TRUE
regmatches()
Вытаскиваем все значения строк, которые нашли с помощью regexpr()
## [1] "apple" "apple"
Можно использовать и для замены шаблона в строке, но лучше использовать другие функции, предназначенные для замены.
## [1] "I love orange and apple pie" "Apple ipad"
## [3] "orange ipod"
sub()
и gsub()
Заменяем по шаблону:
Заменяем первое совпадение:
## [1] "I love orange and apple pie" "Apple ipad"
## [3] "orange ipod"
Заменяем все совпадения:
## [1] "I love orange and orange pie" "Apple ipad"
## [3] "orange ipod"
strsplit()
Разделяем каждую строку в массиве по какому-то шаблону. Например, можем разделить по словам с помощью \\W
## [[1]]
## [1] "I" "love" "apple" "and" "apple" "pie"
##
## [[2]]
## [1] "Apple" "ipad"
##
## [[3]]
## [1] "apple" "ipod"
# пишем сам запрос
m <- gregexpr('\\w\\w\\w+', text, perl=TRUE)
# выводим совпадения
regmatches(text, m)
## [[1]]
## [1] "largest" "Analytics" "community" "India"
## [[1]]
## [1] "largest" "Analytics" "community" "India"
## [[1]]
## [,1] [,2]
## [1,] "largest" "la"
## [2,] "Analytics" "An"
## [3,] "community" "co"
## [4,] "India" "In"
email <- 'abc.test@4gmail.com, xyz@test.in, test.first@analyticsvidhya.com, first.test@rest.biz'
regmatches(email, gregexpr('@\\w+', email, perl=TRUE))
## [[1]]
## [1] "@4gmail" "@test" "@analyticsvidhya" "@rest"
dates <- 'Amit 34-3456 12-05-2007, XYZ 56-4532 11-11-2011, ABC 67-8945 12-01-2009'
regmatches(dates, gregexpr('\\d+-\\d+-\\d+', dates, perl=TRUE))
## [[1]]
## [1] "12-05-2007" "11-11-2011" "12-01-2009"
## [1] "Маша съела пару пирогов сегодня"
text <- '<div class="wall_post_text">«Индексы в IntelliJ IDEA зависят только от содержимого одного файла. С одной стороны, это очень удобно. С другой стороны, это накладывает большие ограничения на то, что можно поместить в индекс».<br><br> О том, как в IntelliJ IDEA ищут лямбда-выражения: <a href="/away.php?to=http%3A%2F%2Famp.gs%2F4iBG&post=-20629724_1179782&cc_key=" target="_blank" rel="noopener">#разработка@habr</a></div>'
gsub('<[^<]+?>', '', text)
## [1] "«Индексы в IntelliJ IDEA зависят только от содержимого одного файла. С одной стороны, это очень удобно. С другой стороны, это накладывает большие ограничения на то, что можно поместить в индекс». О том, как в IntelliJ IDEA ищут лямбда-выражения: #разработка@habr"