Найти тему
Nuances of programming

Краткое руководство по строкам и регулярным выражениям в R

Оглавление

Источник: Nuances of Programming

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

В этом смысле работа со строками требует несколько иного набора навыков, чем работа с теми же списками или data.frame. В текущей статье, как вы уже поняли, мы будем учиться максимально эффективно управлять строками. Начнем!

Вставка и разделение

Вставка и разделение частей строк  —  это две из наиболее типичных задач, с которыми мы встречаемся.

Для них у нас есть две простые функции: paste() и strsplit().

-2

Общее число символов и разделение

У R и Python есть немало общего. Оба этих языка легки в освоении и за счет своих гибких библиотек становятся типичным выбором среди статистов, практиков машинного обучения, да и любых интересующихся наукой о данных людей. Если же вы пришли в R из Python, то примеры, которые я планирую показать, могут показаться вам несколько странными.

Например, для нахождения общего количества символов интуитивным выбором будет lengh(). Но в R это происходит не так, как в Python.

-3

Разделение здесь тоже отличается. Для этого у нас есть две функции: substr() и substring(). Они работают абсолютно одинаково, если указать параметры начала и завершения. Тем не менее у substring() есть предустановленное стоп-значение, а у substr() нет.

-4

Вот что происходит, если не передать аргумент в параметр stop:

-5

regexec() , gregexpr() и grep()

Я уже слышу ваш вопрос: “А откуда нам знать индексы для передачи аргументов?”. Что ж, когда у вас всего один фрагмент строки, то это несложно подсчитать на пальцах, но в случае миллионов, да даже десятков, строк данных такой подход не сгодится. К счастью, у нас есть для этого две прекрасные функции.

Первая из них, regexec(), используется для поиска первого вхождения подстроки внутри большой строки.

-6

При этом gregexpr() находит все вхождения подстроки.

-7

Функция grep() получает второй аргумент, который отражает уже не фрагмент строки, а вектор строк. В ответ же она возвращает индексы элементов, которые содержат искомую подстроку. Если дополнительно установить значение параметра на T (TRUE), функция вернет сами элементы.

-8

sub() и gsub()

sub() и gsub() идут еще дальше и заменяют часть большой строки, соответствующую заданной подстроке, строкой, переданной в качестве аргумента.

-9

Если вы заметили, что слово “America” осталось прежним, то дело в том, что sub() заменяет только первое вхождение подстроки. Для замены всех мы используем gsub().

-10

Регулярные выражения (REGEX)

До этого момента мы искали простые фрагменты подстрок внутри других строк. Но искомая подстрока может быть не такой простой, как в примерах. Мы даже можем не знать, какую конкретно подстроку нужно найти, и искать такую, которая будет вписываться в определенную модель. В подобных случаях мы задействуем регулярные выражения, или regex.

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

Регулярные выражения не получают точную подстроку, которую нужно найти. Вместо этого они ищут такие подстроки, которые вписываются в переданный им паттерн. Для этого у них есть собственный мини-язык и метасимволы. Я подробно объясню все метасимволы и правила, которые определяют работу регулярного выражения.

Метасимволы

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

  • “$”
  • “*”
  • “+”
  • “.”
  • “?”
  • “[ ]”
  • “^”
  • “{ }”
  • “|”
  • “( )”
  • “\ ”

Далее я объясню действие каждого из этих метасимволов.

Квантификаторы

Среди метасимволов знаки “?” , “*” , “+” и “{ }” называются квантификаторами, потому что указывают, сколько раз мы хотим увидеть заданный паттерн.

  • “*”: предыдущий элемент должен встречаться 0 или более раз.
  • “+”: предыдущий элемент должен встречаться 1 или более раз.
  • “?”: предыдущий элемент должен встречаться 0 или 1 раз.
  • “{ ,m}”: предыдущий элемент должен встречаться m или меньше раз.
  • “{n, }”: предыдущий элемент должен встречаться n или более раз.
  • “{n , m}”: предыдущий элемент должен встречаться от n до m раз.
  • “{m}”: предыдущий элемент должен встречаться ровно m раз.
-11
-12

Метасимволы начала и завершения

Символы “^” и “$” представляют начало и конец строки соответственно. Иногда их еще называют якорями. При этом они никаким символам не соответствуют.

-13

Плейсхолдер

Следующий метасимвол  —  это “.”, который соответствует любому символу в том месте, где используется. В примере ниже ищется любой паттерн, начинающийся с “C”, заканчивающийся на “A” и имеющий между этими символами любые два символа.

-14

Последовательности

Метасимвол “\” при использовании с набором ключевых букв служит для определения конкретной последовательности символов в строке и сопоставляется с этой последовательностью при использовании в функциях для строк. Ниже приводится список ключевых букв, которые часто используются с этим метасимволом:

  • “\d” = цифра;
  • “\D” = не цифра;
  • “\w” = словесный символ (a-z, A-Z, 0???9);
  • “\W” = не словесный символ;
  • “\s” = пробельный символ;
  • “\S” = не пробельный символ;
  • “\b” = граница слова;
  • “\B” = не граница слова.

Вот примеры:

-15

Символьные классы

Еще один метасимвол  —  это “[ ]”, который зачастую служит для формирования комплексных паттернов при анализе сложных и неструктурированных текстовых данных. В эти квадратные скобки можно передать несколько символов, в результате чего будут найдены только они, но не вместе, а по-отдельности, порядок при этом значения не имеет. Также можно указывать диапазон искомых символов с помощью дефиса.

-16

В определенных случаях можно заключать в квадратные скобки встроенные имена классов. Ниже приводится полный список таких имен.

  • [:alnum:] = буквенно-цифровые символы: [:alpha:] и [:digit:].
  • [:alpha:]= буквенные символы: [:lower:] и [:upper:].
  • [:blank:]= пустые символы: пробелы и табуляции, а также определяемые языковым стандартом, например неразрывный пробел.
  • [:cntrl:] = управляющие символы в ASCII. Эти символы имеют восьмеричные коды от 000 до 037 и 177 (DEL). В других наборах символов они являются равнозначными, если присутствуют.
  • [:digit:] = цифры: 0 1 2 3 4 5 6 7 8 9.
  • [:graph:] = графические символы: [:alnum:] и [:punct:].
  • [:lower:] = буквы нижнего регистра в текущем языковом стандарте.
  • [:print:] = печатные символы: [:alnum:], [:punct:] и пробел.
  • [:punct:] = знаки препинания: ! “ # $ % & ’ ( ) * + , — / : ; < = > ? @ [ ] ^ _ ` { | } ~. “.
  • [:space:] = пробельные символы: табуляция, новая строка, вертикальная табуляция, возврат каретки, перевод страницы, а также другие символы, определяемые различными языковыми стандартами.
  • [:upper:] = буквы верхнего регистра в текущем языковом стандарте.
  • [:xdigit:] = шестнадцатеричные цифры: 0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f.

Группировка и оператор ИЛИ

Последними метасимволами у нас идут “()” и “|”, которые обычно используются вместе. С помощью скобок мы обособляем нужные наборы символов, а оператор ИЛИ позволяет указывать на возможность выбора между ними. Вот примеры:

-17

Экранирование

Мы рассмотрели все метасимволы, но что, если искомый паттерн содержит один из них?

Это очевидный и ожидаемый вопрос. В таком случае нужно сообщить R, что этот символ нужно рассматривать не как метасимвол, а как обычный знак.

Для этого мы добавляем тот же обратный слэш “\” перед нужным метасимволом, экранируя его. А поскольку обратный слэш сам является метасимволом, мы добавляем к нему еще один слэш для экранирования. Вот примеры:

-18

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

Читайте также:

Читайте нас в Telegram, VK

Перевод статьи Uğurcan Demir: A Concise Guide for Strings and Regular Expressions in R