2017-04-18 24 views
1

我期望從列中的條目(user_entry)具有不同格式並且每行可能包含多個實例的數據創建查找表。從定義不明的用戶輸入數據中提取多個字符串

# create example dataframe. 
id <- c(1111,1112,1113,1114) 
user_entry <- c("999/1001","1002;1003","999/1004\n999/1005","9991006 9991007") 
df <- data.frame(id,user_entry) 

> df 
    id   user_entry 
1 1111   999/1001 
2 1112   1002;1003 
3 1113 999/1004\n999/1005 
4 1114 9991006 9991007 

我只在其可以或可以不被一個3位的位置的代碼和/或分隔符之前諸如「/」或空間中的4位代碼感興趣。每個條目中可能有多個4位數的代碼,我想在最終的查找表中分別列出每個代碼(請參見下面的lookup)。

下面的代碼做我正在尋找,但真正不合適循環內循環和內部增長的數據框。有沒有更好的方法來做到這一點?

library(dplyr);library(stringr) 

# use stringr package to extract only digits 
df <- df %>% 
mutate(entries = str_extract_all(user_entry,"[[:digit:]]+")) %>% 
select(-user_entry) 

# initialise lookup dataframe 
lookup <- df[FALSE,] 
for (record in 1:nrow(df)){ 
    entries <- df$entries[[record]]  
    for (element in 1:length(entries)){ 
    # only interested in 4 digit codes 
    if (nchar(entries[element])>3){ 
     # remove 3 digit code if it is still attached 
     lookup_entry <- gsub('.*?(\\d{4})$','\\1',entries[element]) 
     lookup <- rbind(lookup,data.frame(id=df$id[[record]],entries=lookup_entry)) 
    } 
    } 
} 

> lookup 
    id entries 
1 1111 1001 
2 1112 1002 
3 1112 1003 
4 1113 1004 
5 1113 1005 
6 1114 1006 
7 1114 1007 
+0

也許你可以提取每一個數字的最後4位數字序列? ['str_extract_all(user_entry, 「\\ d {4} \\ B」)'](https://regex101.com/r/Hm20nm/1)? –

回答

2

使用基礎R,

matches <- regmatches(user_entry, gregexpr("(\\d{4})\\b", user_entry)) 

data.frame(
    id = rep(id, lengths(matches)), 
    entries = unlist(matches), 
    stringsAsFactors = FALSE 
) 
#  id entries 
# 1 1111 1001 
# 2 1112 1002 
# 3 1112 1003 
# 4 1113 1004 
# 5 1113 1005 
# 6 1114 1006 
# 7 1114 1007 
+0

這使得假設,如果我們將始終有4位數字之前的999。我不知道這是否會始終如此。如果最後一項是1007999,那麼正則表達式將返回7999. – Kristofersen

+0

除此之外,它是比我更清潔的解決方案。想像我會發布,但OPs的好處。我不確定他究竟該如何處理999s – Kristofersen

+0

這些模式表明(不管「999」)4位數的興趣代碼總是在右邊,這在示例中是足夠的。將SO問題簡化爲「最小/可重複」的風險是過度簡化,沒有提供足夠的多樣性。 \ *聳肩\ * – r2evans

0

不是很優雅,但我認爲它應該工作你的情況:

library("tidyverse") 
df1 <- df %>% 
    separate_rows(user_entry, sep = '(/|;|\\n|\\s)') 

extract <- str_extract(df1$user_entry,"(?=\\d{3})\\d{4}$") 
df1$extract <- extract 
df2 <- df1[!is.na(df1$extract),] 
df2 


> df2 
    id user_entry extract 
#1111  1001 1001 
#1112  1002 1002 
#1112  1003 1003 
#1113  1004 1004 
#1113  1005 1005 
#1114 9991006 1006 
#1114 9991007 1007 
相關問題