แยกการจับคู่นิพจน์ทั่วไป


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"

3
(เกือบ) ตรงกับสิ่งที่ฉันต้องการ แต่เมื่อฉันเริ่มพิมพ์?str_extractฉันเห็นstr_extract_allและชีวิตก็ดีขึ้นอีกครั้ง
dwanderson

94

อาจเป็นเรื่องที่ค่อนข้างรีบร้อนที่จะพูดว่า ' ละเว้นฟังก์ชันมาตรฐาน ' ซึ่งเป็นไฟล์ช่วยเหลือสำหรับ?gsubการอ้างอิงโดยเฉพาะใน 'ดูเพิ่มเติม':

'regmatches' สำหรับการแยกสตริงย่อยที่ตรงกันโดยพิจารณาจากผลลัพธ์ของ 'regexpr', 'gregexpr' และ 'regexec'

สิ่งนี้จะได้ผลและค่อนข้างง่าย:

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


15

คุณสามารถใช้การจับคู่แบบขี้เกียจของ PERL regexs:

> 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 เปรียบเสมือนใช้โดยที่ args เป็นวัตถุตัวปรับแต่งและฟังก์ชันยกเว้นว่าวัตถุนั้นเป็นเวกเตอร์ของสตริง (แทนที่จะเป็นอาร์เรย์) และตัวปรับเปลี่ยนเป็นนิพจน์ทั่วไป (แทนที่จะเป็นระยะขอบ):

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

สิ่งนี้ระบุว่าจะจับคู่ตัวเลขอย่างน้อยหนึ่งตัว (\ d +) ในแต่ละองค์ประกอบของ x ที่ส่งผ่านการจับคู่แต่ละครั้งเป็นตัวเลข จะส่งคืนรายการที่มีส่วนประกอบเป็นเวกเตอร์ของการจับคู่ของส่วนประกอบต่างๆของ x เมื่อดูผลลัพธ์ที่ออกเราจะเห็นว่าองค์ประกอบแรกของ x มีการจับคู่หนึ่งรายการซึ่งเป็น 13 และองค์ประกอบที่สองของ x มีการจับคู่สองรายการคือ 12 และ 34 ดูข้อมูลเพิ่มเติมที่http://gsubfn.googlecode.com



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  

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 โดยแพ็คเกจ reprex (v0.3.0)

ใช้convertอาร์กิวเมนต์เพื่อแปลงเป็นตัวเลขโดยอัตโนมัติ:

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

-2

คุณสามารถเขียนฟังก์ชัน regex ของคุณด้วย 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.
Daniel Hoop
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.