R regex - извлечь слова, начинающиеся с символа @ - PullRequest
5 голосов
/ 14 марта 2019

Я пытаюсь извлечь твиттеры из твитов, используя stringr пакет R .Например, предположим, что я хочу получить все слова в векторе, которые начинаются с «А».Я могу сделать это так

library(stringr)

# Get all words that begin with "A"
str_extract_all(c("hAi", "hi Ahello Ame"), "(?<=\\b)A[^\\s]+")

[[1]]
character(0)

[[2]]
[1] "Ahello" "Ame"   

Отлично.Теперь давайте попробуем то же самое, используя «@» вместо «A»

str_extract_all(c("h@i", "hi @hello @me"), "(?<=\\b)\\@[^\\s]+")

[[1]]
[1] "@i"

[[2]]
character(0)

Почему этот пример дает противоположный результат, который я ожидал, и как я могу это исправить?

Ответы [ 3 ]

4 голосов
/ 14 марта 2019

Похоже, вы, вероятно, имеете в виду

str_extract_all(c("h@i", "hi @hello @me", "@twitter"), "(?<=^|\\s)@[^\\s]+")
# [[1]]
# character(0)
# [[2]]
# [1] "@hello" "@me" 
# [[3]]
# [1] "@twitter"

* Регулярное выражение \b является границей, и это происходит "между двумя символами в строке, где один является символом слова, а другой -не слово характер. " см. Здесь .Поскольку пробел и «@» являются несловесными символами, перед «@» нет границы.

С помощью этой ревизии вы сопоставляете либо начало строки, либо значения, которые идут после пробелов.

2 голосов
/ 15 марта 2019

Несколько вещей о вашем регулярном выражении:

  • (?<=\b) совпадает с \b, поскольку граница слова уже является утверждением нулевой ширины
  • \@так же, как @, так как @ не является специальным метасимволом регулярных выражений, и вам не нужно экранировать его
  • [^\s]+ совпадает с \S+, почти все классы сокращенных символов имеют свои отрицательныедубликаты в регулярном выражении.

Итак, ваше регулярное выражение, \b@\S+, соответствует @i в h@i, поскольку существует граница слова между h (буква, слово char) и @ (не словесный символ, а не буква, цифра или знак подчеркивания).Проверьте этот отладчик регулярных выражений .

\b - это неоднозначный шаблон, значение которого зависит от контекста регулярных выражений .В вашем случае вы можете захотеть использовать \B, границу, не состоящую из слов, то есть \B@\S+, и она будет соответствовать @, которым предшествует символ без слова или в начале строки.

x <- c("h@i", "hi @hello @me")
regmatches(x, gregexpr("\\B@\\S+", x))
## => [[1]]
## character(0)
## 
## [[2]]
## [1] "@hello" "@me"   

См. Демонстрационную версию regex .

Если вы хотите избавиться от этой \b / \B неоднозначности,используйте однозначные границы слов, используя обходные пути с методами stringr или базовые регулярные функции R с аргументом perl=TRUE:

regmatches(x, gregexpr("(?<!\\w)@\\S+", x, perl=TRUE))
regmatches(x, gregexpr("(?<!\\S)@\\S+", x, perl=TRUE))

где:

  • (?<!\w) - однозначный стартграница слова - это отрицательный вид сзади, который гарантирует, что слева от текущего местоположения или начала строки находится символ без слова
  • (?<!\S) - граница начального слова с пробелом - это отрицательный вид сзади, который гарантирует наличие пробела слева от текущего местоположения или начала строки.

См. это демонстрационное выражение regex и еще одна демонстрация регулярных выражений здесь .

Обратите внимание, что сосоответствующие правые границы (?!\w) и (?!\S).

0 голосов
/ 14 марта 2019

Ответа выше должно быть достаточно. Это удалит символ @ в случае, если вы пытаетесь получить только имена пользователей.

str_extract_all(c("@tweeter tweet", "h@is", "tweet @tweeter2"), "(?<=\\B\\@)[^\\s]+")
[[1]]
[1] "tweeter"

[[2]]
character(0)

[[3]]
[1] "tweeter2"

Хотя я не специалист по регулярным выражениям, похоже, проблема в том, что символ @ не соответствует символу слова, и, следовательно, сопоставление пустой строки в начале слова (\\b) не работает потому что нет пустой строки, когда @ предшествует слову.

Вот два замечательных ресурса для регулярных выражений на случай, если вы их не видели:

...