2013-02-26 4 views
3

Скажем, у меня есть вектор строк, как это:Извлечение значений из строк с повторяющимися структуру

vectorOfStrings <- c("Name: Andrew, College: Bradford", 
        "Name: Charlie Daniels, College: Easton College", 
        "Name: Frank Gehry, III, College: Highlands University") 

где существует четкое повторение «Имя:», «Колледж:» шаблон.

Я хотел бы получить список (или data.frame), который выглядит следующим образом:

listOfValues <- list(c("Andrew", "Charlie Daniels", "Frank Gehry, III"), 
        c("Bradford", "Easton College", "Highlands University")) 

Самый простой способ получить от vectorOfStrings до listOfValues? Я достаточно хорошо знаком с функциями управления строкой base, а также с stringr, но я бы предположил, что это довольно распространенная ситуация, и я надеюсь, что существует относительно хорошо разработанное решение.

Заранее спасибо.

ответ

1

я такого рода вещи с regexp, используя perl=T) (не нашел хороший способ извлечения захваченных групп в противном случае):

m <- regexpr('^Name: *(.+), *College: (.+) *$', 
      vectorOfStrings, perl=T) 
# m looks like this: 
# [1] 1 1 1 
# attr(,"match.length") 
# [1] 31 46 53 
# attr(,"useBytes") 
# [1] TRUE 
# attr(,"capture.start") # one column per capturing bracket, 
# [1,] 7 24    # one row per entry in vectorOfStrings 
# [2,] 7 33 
# [3,] 7 34 
# attr(,"capture.length")  
# [1,] 6 8 
# [2,] 15 14 
# [3,] 16 20 
# attr(,"capture.names") 
# [1] "" "" 

# laziness 
st <- attr(m, 'capture.start') 
en <- st + attr(m, 'capture.length') - 1 
numCaptures <- ncol(st) 

matches <- sapply(1:numCaptures, function (i) { 
    return(substr(vectorOfStrings, st[, i], en[, i])) 
}) 

# matches 
#  [,1]    [,2]     
# [1,] "Andrew"   "Bradford"    
# [2,] "Charlie Daniels" "Easton College"  
# [3,] "Frank Gehry, III" "Highlands University" 

Теперь массаж matches в нужной форме. Обычно я обертываю это функцией, поскольку я использую ее довольно часто.

Вы можете даже использовать Perl регулярное выражение именования как так:

m <- regexpr('^Name: *(?<name>.+), *College: (?<college>.+) *$', 
      vectorOfStrings, perl=T) 

, а затем attr(m, 'capture.names') будет c('name', 'college') и colnames(attr(m, 'capture.(start or length)')) также c('name', 'college').

В любом случае ключ, кажется, использует perl=T, иначе regexpr не возвращает набор начальных/конечных точек на захватный кронштейн.

+0

(в качестве альтернативы вы можете разделить на ':' и обрезать значения предыдущих пробелов или запятых и пробелов, если вы уверены, что ':' не будет отображаться внутри ни в одном из имен или колледжей) –

3

Мне нравится идея математического КОФЕ, но так как я уже получил это написано выше, вот еще одна возможность:

X <- strsplit(vectorOfStrings, ",\\s*(?=College:)", perl=TRUE) 
do.call(rbind, lapply(X, function(X) gsub("(Name|College):\\s*", "", X))) 
#  [,1]    [,2]     
# [1,] "Andrew"   "Bradford"    
# [2,] "Charlie Daniels" "Easton College"  
# [3,] "Frank Gehry, III" "Highlands University" 
1

вероятно проще использовать ссылочность

> vectorOfStrings 
[1] "Name: Andrew, College: Bradford"      "Name: Charlie Daniels, College: Easton College"  
[3] "Name: Frank Gehry, III, College: Highlands University" 
> list(gsub('^Name:(.*), College:(.*)$',"\\1", vectorOfStrings) , gsub('^Name:(.*), College:(.*)$',"\\2", vectorOfStrings)) 
[[1]] 
[1] " Andrew"   " Charlie Daniels" " Frank Gehry, III" 

[[2]] 
[1] " Bradford"    " Easton College"  " Highlands University" 
4

Вот два возможных решения:

(1) strapplyc Оператор mat создает матрицу, первая колонка которой содержит e, а второй - колледжи. Затем мы преобразуем, что неназванный список в последнем заявлении:

library(gsubfn) 

pat <- "Name: (.*), College: (.*)" 
mat <- strapplyc(vectorOfStrings, pat, simplify = rbind) 

unname(as.list(as.data.frame(mat, stringsAsFactors = FALSE))) 

(2) GSUB/read.table Разновидности используя только обычный R является использование gsub с pat сверху, чтобы преобразовать каждую входную строку строка, разделенная на трубы, содержащая данные, но не теги. Чтение, что с помощью read.table дает кадр данных, DF.Наконец, мы преобразуем DF неназванный список:

g <- gsub(pat, "\\1|\\2", vectorOfStrings) 
DF <- read.table(text = g, sep = "|", as.is = TRUE) 

unname(as.list(DF)) 

ДОБАВЛЕНО: второе решение

2
do.call(rbind, strsplit(unlist(
      strsplit(vectorOfStrings, "Name: ")), ", College: ")) 

     [,1]    [,2]     
    [1,] "Andrew"   "Bradford"    
    [2,] "Charlie Daniels" "Easton College"  
    [3,] "Frank Gehry, III" "Highlands University" 


, кажется, есть много хороших ответы уже. Подобно @Josh O'Brien, я бы использовал strsplit.

Поскольку вы не храните "Name" и "College", вы можете разделить его прямо на него. Затем вы просто запустили это в do.call(rbind, ___), который автоматически удалит любые пустые строки, созданные разделом.

Смежные вопросы