簡體   English   中英

如何用正則表達式提取R中字符串的不匹配部分?

[英]How can I extract the unmatched portion of a string in R with regular expressions?

我有一個非常凌亂的字符串向量。 這是一個例子:

library(tidyverse)
library(stringr)
strings <- tibble(
  name = c("lorem 11:07:59 86136-1-sed", 
           "ipsum 14:35:57 S VARNAME-ut",
           "dolor 10:37:53 1513 -2-perspiciatis",
           "sit 10:48:25",
           "amet 13:52:1365293-2-unde",
           "consectetur 11:53:1 16018-2-omnis",
           "adipiscing 11:19 17237-2-iste"
           )
)
strings_out <- strings %>% 
  mutate(heads = str_extract(name, "^.*?\\s\\d{1,2}:\\d{1,2}:\\d{1,2}")) %>% 
  mutate(ends = str_replace(name, "^.*?\\s\\d{1,2}:\\d{1,2}:\\d{1,2}", ""))
strings_out[,2:3]
#> # A tibble: 7 x 2
#>                 heads                          ends
#>                 <chr>                         <chr>
#> 1      lorem 11:07:59                   86136-1-sed
#> 2      ipsum 14:35:57                  S VARNAME-ut
#> 3      dolor 10:37:53          1513 -2-perspiciatis
#> 4        sit 10:48:25                              
#> 5       amet 13:52:13                  65293-2-unde
#> 6 consectetur 11:53:1                 16018-2-omnis
#> 7                <NA> adipiscing 11:19 17237-2-iste

所以這里我有一些字符串,其中包含一些文本,然后是可能正確輸入或未正確輸入的時間,然后是更多文本。 我想在時間之后只提取字符串的末尾,但是它們沒有任何模式似乎與使用str_extract的潛在正則表達式很好地對應。 我可以輕松匹配琴弦的前半部分,如heads所示。 但是,我發現提取后半部分的唯一方法是使用帶有空字符串的str_replace ,如ends所示。

我試圖在這個列表中包含我注意到的所有常見錯誤:時間后沒有關於連字符,間隔或字符串內容的模式,沒有保證時間和字符串所需的結束一半,時間丟失數字甚至是數字冒號。

我想做的是能夠使用str_extract來獲得與str_replace相近的東西。 關鍵的區別在於,對於這個正則表達式仍然不起作用的錯誤, str_extract給了我一個易於過濾和手動修復的NA ,但是str_replace只復制整個字符串,如第7行所示。

我懷疑我可以使用更多hacky方法來做到這一點,例如獲取所有NA並在Excel或其他東西中手動修復,但我很驚訝我無法弄清楚如何返回字符串中不匹配的部分,盡管有一堆搜索並嘗試包含(^)[^]不同正則表達式。 有任何想法嗎?

在一般情況下,你可能會想看看lookarounds ,但您的數據可能需要更多的結構對他們是有用的。

這是我寫的一個簡單的例子,我知道時間之后並不總是有空格:


library(tidyverse)
library(stringr)
strings <- tibble(
  name = c("lorem 11:07:59 86136-1-sed", 
           "ipsum 14:35:57 S VARNAME-ut",
           "dolor 10:37:53 1513 -2-perspiciatis",
           "sit 10:48:25",
           "amet 13:52:1365293-2-unde",
           "consectetur 11:53:1 16018-2-omnis",
           "adipiscing 11:19 17237-2-iste"
  )
)
strings_out <- strings %>% 
  mutate(heads = str_extract(name, "^.*?\\s\\d{1,2}:\\d{1,2}:\\d{1,2}"),
         ends = str_extract(name, "(?<=:\\d{1,2} )[\\s\\S]+$"))

strings_out[c(1,3)]
#> # A tibble: 7 x 2
#>                                  name                 ends
#>                                 <chr>                <chr>
#> 1          lorem 11:07:59 86136-1-sed          86136-1-sed
#> 2         ipsum 14:35:57 S VARNAME-ut         S VARNAME-ut
#> 3 dolor 10:37:53 1513 -2-perspiciatis 1513 -2-perspiciatis
#> 4                        sit 10:48:25                 <NA>
#> 5           amet 13:52:1365293-2-unde                 <NA>
#> 6   consectetur 11:53:1 16018-2-omnis        16018-2-omnis
#> 7       adipiscing 11:19 17237-2-iste         17237-2-iste

這里的問題是第5行。如果沒有更多結構,我們無法知道時間是13:52:13還是13:52:1 ,因為兩者都是其他字符串中的選項。 確定哪個是正確的不是可以用正則表達式解決的問題。

你也可以試試這個:

library(tidyverse)
library(stringr)

regex = "^\\w+\\s\\d{2}:\\d{2}:*\\d{0,2}"

strings %>%
  mutate(head = str_extract(name, regex),
         end = str_replace(name, paste0(regex, "\\s?"), ""),
         end = str_replace(end, "^\\s*$", NA_character_))

結果:

# A tibble: 7 x 3
                                 name                head                  end
                                <chr>               <chr>                <chr>
1          lorem 11:07:59 86136-1-sed      lorem 11:07:59          86136-1-sed
2         ipsum 14:35:57 S VARNAME-ut      ipsum 14:35:57         S VARNAME-ut
3 dolor 10:37:53 1513 -2-perspiciatis      dolor 10:37:53 1513 -2-perspiciatis
4                        sit 10:48:25        sit 10:48:25                 <NA>
5           amet 13:52:1365293-2-unde       amet 13:52:13         65293-2-unde
6   consectetur 11:53:1 16018-2-omnis consectetur 11:53:1        16018-2-omnis
7       adipiscing 11:19 17237-2-iste    adipiscing 11:19         17237-2-iste

注意:

我的解決方案適用於第5行,但在這種情況下,您必須決定是否要提取13:52:1313:52:1 這兩種情況都可以通過對正則表達式的簡單修改來完成,但正如@Zach所述,沒有自動方式。

只需一行即可獲得:

strings["rx"] <- str_match(strings$name, "\\d*:\\d*(?::\\d+)?(.*)")[,2]
strings

哪個收益率

# A tibble: 7 x 2
                                 name                    rx
                                <chr>                 <chr>
1          lorem 11:07:59 86136-1-sed           86136-1-sed
2         ipsum 14:35:57 S VARNAME-ut          S VARNAME-ut
3 dolor 10:37:53 1513 -2-perspiciatis  1513 -2-perspiciatis
4                        sit 10:48:25                      
5           amet 13:52:1365293-2-unde               -2-unde
6   consectetur 11:53:1 16018-2-omnis         16018-2-omnis
7       adipiscing 11:19 17237-2-iste          17237-2-iste

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM