Извлечь совпадение с регулярным выражением

112

Я пытаюсь извлечь число из строки.

И сделай что-то вроде [0-9]+на веревочке "aaa12xxx"и получишь "12".

Я думал, это будет что-то вроде:

> grep("[0-9]+", "aaa12xxx", value=TRUE)
[1] "aaa12xxx"

А потом я подумал ...

> sub("[0-9]+", "\\1", "aaa12xxx")
[1] "aaaxxx"

Но я получил ответ:

> sub("[0-9]+", "ARGH!", "aaa12xxx")
[1] "aaaARGH!xxx"

Мне не хватает одной маленькой детали.

Товаре
источник

Ответы:

167

Используйте новый пакет stringr, который обертывает все существующие регулярные выражения, работает с согласованным синтаксисом, и добавляет некоторые из них, которые отсутствуют:

library(stringr)
str_locate("aaa12xxx", "[0-9]+")
#      start end
# [1,]     4   5
str_extract("aaa12xxx", "[0-9]+")
# [1] "12"
Hadley
источник
3
(почти) именно то, что мне нужно, но когда я начал печатать, ?str_extractя увидел, что str_extract_allжизнь снова стала хорошей.
dwanderson
94

Наверное, будет поспешно сказать « игнорировать стандартные функции » - файл справки ?gsubдаже для конкретных ссылок в «См. Также»:

regmatches для извлечения совпадающих подстрок на основе результатов regexpr, gregexpr и regexec.

Итак, это будет работать, и это довольно просто:

txt <- "aaa12xxx"
regmatches(txt,regexpr("[0-9]+",txt))
#[1] "12"
thelatemail
источник
27

Может быть

gsub("[^0-9]", "", "aaa12xxxx")
# [1] "12"
Марек
источник
15

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

> sub(".*?([0-9]+).*", "\\1", "aaa12xx99",perl=TRUE)
[1] "12"

Попытка заменить нецифровые цифры в этом случае приведет к ошибке.

Джйотирмой Бхаттачарья
источник
4
Не нужен PERL, если вы хотите использовать немного более уродливое "[^ 0-9] * ([0-9] +). *"
Джйотирмой Бхаттачарья
5

Один из способов был бы таким:

test <- regexpr("[0-9]+","aaa12456xxx")

Обратите внимание, что regexpr дает вам начальный и конечный индексы строки:

    > test
[1] 4
attr(,"match.length")
[1] 5

Таким образом, вы можете использовать эту информацию с функцией substr

substr("aaa12456xxx",test,test+attr(test,"match.length")-1)

Я уверен, что есть более элегантный способ сделать это, но это был самый быстрый способ, который я смог найти. В качестве альтернативы вы можете использовать sub / gsub, чтобы удалить то, что вы не хотите, оставлять то, что вам нужно.

Роберт
источник
5

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

gsub('([[:alpha:]]+)([0-9]+)([[:alpha:]]+)', '\\2', "aaa12xxx")
Рэги Исаак
источник
2

Использование strapply в пакете gsubfn. strapply похож на apply в том, что аргументы являются объектом, модификатором и функцией, за исключением того, что объект является вектором строк (а не массивом), а модификатор является регулярным выражением (а не полем):

library(gsubfn)
x <- c("xy13", "ab 12 cd 34 xy")
strapply(x, "\\d+", as.numeric)
# list(13, c(12, 34))

Это говорит о совпадении одной или нескольких цифр (\ d +) в каждом компоненте x, передавая каждое совпадение через as.numeric. Он возвращает список, компоненты которого являются векторами совпадений соответствующих компонентов x. Глядя на выходные данные, мы видим, что первый компонент x имеет одно совпадение, равное 13, а второй компонент x имеет два совпадения: 12 и 34. Подробнее см. Http://gsubfn.googlecode.com .

Г. Гротендик
источник
1

Другое решение:

temp = regexpr('\\d', "aaa12xxx");
substr("aaa12xxx", temp[1], temp[1]+attr(temp,"match.length")[1])
пари
источник
1

Решение этого вопроса

library(stringr)
str_extract_all("aaa12xxx", regex("[[:digit:]]{1,}"))
# [[1]]
# [1] "12"

[[: digit:]] : цифра [0-9]

{1,} : соответствует минимум 1 раз

Тхо Ву
источник
0

Одно важное различие между этими подходами - поведение при любых несовпадениях. Например, метод regmatches может не возвращать строку той же длины, что и входные данные, если нет совпадений во всех позициях.

> txt <- c("aaa12xxx","xyz")

> regmatches(txt,regexpr("[0-9]+",txt)) # could cause problems

[1] "12"

> gsub("[^0-9]", "", txt)

[1] "12" ""  

> str_extract(txt, "[0-9]+")

[1] "12" NA  
andyyy
источник
0

Используя пакет unglue, мы сделаем следующее:

# install.packages("unglue")
library(unglue)
unglue_vec(c("aaa12xxx", "aaaARGH!xxx"), "{prefix}{number=\\d+}{suffix}", var = "number")
#> [1] "12" NA

Создано 2019-11-06 пакетом REPEX (v0.3.0)

Используйте convertаргумент для автоматического преобразования в число:

unglue_vec(
  c("aaa12xxx", "aaaARGH!xxx"), 
  "{prefix}{number=\\d+}{suffix}", 
  var = "number", 
  convert = TRUE)
#> [1] 12 NA
Moody_Mudskipper
источник
-2

Вы можете написать свои регулярные функции с помощью C ++, скомпилировать их в DLL и вызвать их из R.

    #include <regex>

    extern "C" {
    __declspec(dllexport)
    void regex_match( const char **first, char **regexStr, int *_bool)
    {
        std::cmatch _cmatch;
        const char *last = *first + strlen(*first);
        std::regex rx(*regexStr);
        bool found = false;
        found = std::regex_match(*first,last,_cmatch, rx);
        *_bool = found;
    }

__declspec(dllexport)
void regex_search_results( const char **str, const char **regexStr, int *N, char **out )
{
    std::string s(*str);
    std::regex rgx(*regexStr);
    std::smatch m;

    int i=0;
    while(std::regex_search(s,m,rgx) && i < *N) {
        strcpy(out[i],m[0].str().c_str());
        i++;
        s = m.suffix().str();
    }
}
    };

позвонить в R как

dyn.load("C:\\YourPath\\RegTest.dll")
regex_match <- function(str,regstr) {
.C("regex_match",x=as.character(str),y=as.character(regstr),z=as.logical(1))$z }

regex_match("abc","a(b)c")

regex_search_results <- function(x,y,n) {
.C("regex_search_results",x=as.character(x),y=as.character(y),i=as.integer(n),z=character(n))$z }

regex_search_results("aaa12aa34xxx", "[0-9]+", 5)

источник
4
Это совершенно не нужно. См. Ответы thelatemail или Robert, чтобы найти простое решение внутри R.
Дэниел Хуп