Регулярное выражение в R: сопоставить словосочетания слова узла - PullRequest
2 голосов
/ 28 января 2020

Я хочу найти словосочетания слова в текстовых строках. Словосочетания - это те слова, которые встречаются с ним либо перед, либо после него. Вот выдуманный пример:

GO <- c("This little sentence went on and on.", 
        "It was going on for quite a while.", 
        "In fact it has been going on for ages.", 
        "It still goes on.", 
        "It would go on even if it didn't.")

Допустим, меня интересуют слова, сопоставленные с леммой GO, включая все формы, которые может принимать глагол 'go', а именно 'go ',' пошел ',' ушел ',' идет 'и' идет ', и я хочу извлечь оба коллоката слева и справа от GO, используя str_extract из пакета stringr, и собрать коллокаты в кадре данных. Это все хорошо, что касается однословных словосочетаний. Я могу сделать это так:

collocates <- data.frame(
  Left = str_extract(GO, "\\w+\\b\\s(?=(go(es|ing|ne)?|went))"),
  Node = str_extract(GO, "go(es|ing|ne)?|went"),
  Right = str_extract(GO, "(?<=go(es|ing|ne)?|went)\\s\\w+\\b"))

Вот результат:

collocates
       Left  Node Right
1 sentence   went    on
2      was  going    on
3     been  going    on
4    still   goes    on
5    would     go    on

Но меня интересует не только слово one до и после GO, но, скажем, до трех слов до и после GO. Теперь использование выражений квантификатора приближает меня к желаемому результату, но не совсем так:

collocates <- data.frame(
  Left = str_extract(GO, "(\\w+\\b\\s){0,3}(?=(go(es|ing|ne)?|went))"),
  Node = str_extract(GO, "go(es|ing|ne)?|went"),
  Right = str_extract(GO, "(?<=go(es|ing|ne)?|went)(\\s\\w+\\b){0,3}"))

И вот результат:

collocates
                   Left  Node       Right
1 This little sentence   went   on and on
2               It was  going            
3          it has been  going            
4             It still   goes            
5    It probably would     go  on even if

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

Ожидаемый результат:

                   Left  Node         Right
1 This little sentence   went     on and on
2               It was  going  on for quite
3          it has been  going   on for ages
4             It still   goes            on
5             It would     go    on even if

1 Ответ

1 голос
/ 30 января 2020

Использование квантификатора {0,3} (что означает совпадение от 0 до 3 предыдущего токена) просто позволит пропустить первое слово в группе совпадений, если максимум не достигнут.

Regular expression visualization

r <- data.frame(
  Right = str_extract(GO, "(?<=go(es|ing|ne)?|went)(\\s\\w+\\b){0,3}"))

Демонстрация Debuggex

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

r <- data.frame(
  Right = str_extract(GO, "(?<=go(es|ing|ne)?|went)(\\s\\w+\\b){1,3}"))

Regular expression visualization

Debuggex Demo

Это можно продемонстрировать, поиграв со значениями квантификатора и соблюдая следующее:

r <- data.frame(
  Right = str_extract(GO, "(?<=go(es|ing|ne)?|went)(\\s\\w+\\b){2,2}"))

print(r)

     Right
1   on and
2   on for
3   on for
4     <NA>
5  on even

В приведенном выше примере мы выбрали {2,2}, (минимум 2 и максимум 2); поскольку в 4-й строке не хватило слов, чтобы захватить ровно 2, мы получаем <NA>.

...