Витягніть збіг регулярного вираження


111

Я намагаюся витягти число з рядка.

І зробіть щось на зразок [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"

3
(майже) саме те, що мені потрібно, але, коли я почав набирати текст, ?str_extractя побачив, str_extract_allі життя знову було гарним.
dwanderson

94

Напевно, трохи поспішно сказати " ігнорувати стандартні функції " - файл довідки для ?gsubнавіть конкретних посилань у "Див. Також":

'регмати' для вилучення відповідних підрядів на основі результатів 'regexpr', 'gregexpr' та 'regexec'.

Отже, це спрацює і досить просто:

txt <- "aaa12xxx"
regmatches(txt,regexpr("[0-9]+",txt))
#[1] "12"


15

Ви можете використовувати ледачі відповідники PERL:

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

Спроба замінити нецифрові цифри призведе до помилки в цьому випадку.


4
Вам не потрібен PERL, якщо ви готові скористатися трохи потворніше "[^ 0-9] * ([0-9] +). *"
Jyotirmoy Bhattacharya

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 - це як застосувати в тому, що аргументи є об'єктом, модифікатором і функцією, за винятком того, що об'єкт є векторним рядком (а не масивом), а модифікатор є регулярним виразом (а не полем):

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

Одна важлива різниця між цими підходами в поведінці з будь-якими невідповідними. Наприклад, метод регматів може не повертати рядок такої ж довжини, що і вхідний, якщо у всіх позиціях немає відповідності

> 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  

1

Рішення цього питання

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

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

{1,} : Матчі принаймні 1 раз


0

Використовуючи пакет для видалення клею, ми зробимо наступне:

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

Створено 2019-11-06 пакетом reprex (v0.3.0)

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

unglue_vec(
  c("aaa12xxx", "aaaARGH!xxx"), 
  "{prefix}{number=\\d+}{suffix}", 
  var = "number", 
  convert = TRUE)
#> [1] 12 NA

-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" або "Роберт" для легкого рішення всередині R.
Daniel Hoop
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.