2017-07-05 3 views
2

Ich möchte eine Zeichenfolge mit R zu analysieren, und ich möchte eine Liste von Objekten erhalten. Klammern, Räume und Komma in der Zeichenfolge, die die Struktur der endgültigen Liste diktieren:Regex Übung in R

1) jedes Paar Klammern durch einen Raum und die Worte in jedem Paar Klammern getrennt wird, hat ein neues Objekt in der Liste zu bilden, ;

2) Wörter in Klammern sind durch ein Komma getrennt und sollten in jedem aufgelisteten Objekt verschiedene Elemente bilden;

3) Die genannte Struktur kann auch in einem Paar Klammern gefunden werden. Hier ist ein Beispiel für die Zeichenfolge:

x <- "(K01596,K01610) (K01689) (K01834,K15633,K15634,K15635) (K00927) (K00134,K00150) (K01803) ((K01623,K01624,K11645) (K03841,K02446,K11532,K01086,K04041),K01622)" 

Die gewünschte Ausgabe sollte dies mag:

list(c("K01596","K01610"), "K01689", c("K01834","K15633","K15634","K15635"), "K00927", c("K00134","K00150"), "K01803", list(list(c("K01623","K01624","K11645"), c("K03841","K02446","K11532","K01086","K04041")), "K01622")) 

Ich schaffe es zu lösen, wie die Analyse zu tun für Fall 1)

match <- gregexpr("\\((?>[^()]|(?R))*\\)", x, perl = T) 
x2 <- as.list(substring(x, match[[1]], match[[1]] + attr(match[[1]], "match.length") - 1)) 

und Fall 2) ist auch einfach, ich kann einfach die Klammern mit gsub entfernen und die Wörter mit strsplit teilen. Das Problem ist, wie Fall 3) zu analysieren, wenn ich einen verschachtelten Ebene wie haben:

((K01623,K01624,K11645) (K03841,K02446,K11532,K01086,K04041),K01622) 

und ich muss ein gelistetes Objekt erhalten, dass eine Liste selbst ist:

list(list(c("K01623","K01624","K11645"), c("K03841","K02446","K11532","K01086","K04041")), "K01622") 

Antwort

1

können Sie Konvertieren Sie zu JSON, und verwenden Sie anschließend jsonlite, um eine Liste zu erstellen. Sobald Sie dies haben, können Sie Ihre Liste beliebig vereinfachen, reduzieren oder neu organisieren.

library(jsonlite) 
library(stringr) 

add_paren <- function(x){ 
    x <- str_sub(x, end = -2) #remove comma 
    paste0("(", x, "), ") #add enclosing paren and return comma 
} 
x <- str_replace_all(x, "\\(\\(.*\\)\\,", add_paren) 

x <- gsub("\\(", "\\[", x) 
x <- gsub("\\)", "\\]", x) 
x <- gsub("\\] \\[", "\\], \\[", x) 

add_quote <- function(x) paste0('"', x, '"') 

x <- str_replace_all(x, "K[0-9]*", add_quote) 
x <- paste0("[", x, "]") 

x2 <- fromJSON(x) 

Resultat:

dput(x2) 

list(c("K01596", "K01610"), "K01689", c("K01834", "K15633", "K15634", 
"K15635"), "K00927", c("K00134", "K00150"), "K01803", list(list(
    c("K01623", "K01624", "K11645"), c("K03841", "K02446", "K11532", 
    "K01086", "K04041")), "K01622")) 

str(x2) 

List of 7 
$ : chr [1:2] "K01596" "K01610" 
$ : chr "K01689" 
$ : chr [1:4] "K01834" "K15633" "K15634" "K15635" 
$ : chr "K00927" 
$ : chr [1:2] "K00134" "K00150" 
$ : chr "K01803" 
$ :List of 2 
    ..$ :List of 2 
    .. ..$ : chr [1:3] "K01623" "K01624" "K11645" 
    .. ..$ : chr [1:5] "K03841" "K02446" "K11532" "K01086" ... 
    ..$ : chr "K01622" 
+0

ich auf diesem Weg ging und dann aufgegeben. Nette Lösung – akrun

+0

Ich bin nicht vertraut mit JSON-Format, aber scheint mein Problem ziemlich gut zu passen! Wenn möglich, möchte ich jedoch, dass das 7. Element der Liste unterschiedlich strukturiert ist. Wenn Sie den letzten Codeabschnitt ausführen, den ich in der Frage gepostet habe, werden Sie sehen, was ich meine –

+0

Ah, habe das nicht verstanden. Ich habe eine Zeile 'x <- str_replace_all (x," \\ (\\ (. * \\) \\, ", add_paren)' hinzugefügt, die sicherstellen soll, dass alles, was einem Muster ((*) entspricht) verschachtelt wird eine Ebene tiefer, das scheint die gewünschte Ausgabe zu liefern –

0

Ich schlage vor, Sie wenden die regex Sie bereits für den Fall 1) rekursiv auf den Eingang gefunden. Das heißt, rufen Sie Ihre rekursive Funktion für jedes gefundene Match auf.

Wenn keine Übereinstimmung gefunden wird, sind Sie in Fall 2) und können einfach strsplit am Eingang verwenden. Ich habe zusammen unter einem Beispiel setzen Funktion:

constructList <- function(x) { 

    matches <- gregexpr("\\((?>[^()]|(?R))*\\)", x, perl = T) 

    if (matches[[1]][1] == -1) { 
    return(strsplit(x, ",")[[1]]) 
    } 

    lapply(
    lapply(1:length(matches[[1]]), function(i) 
             substr(x, 
               matches[[1]][i] + 1, 
               matches[[1]][i] + attr(matches[[1]], "match.length")[i] - 2)), 
    constructList) 

} 

Ausgang scheint OK:

constructList(x) 
[[1]] 
[1] "K01596" "K01610" 

[[2]] 
[1] "K01689" 

[[3]] 
[1] "K01834" "K15633" "K15634" "K15635" 

[[4]] 
[1] "K00927" 

[[5]] 
[1] "K00134" "K00150" 

[[6]] 
[1] "K01803" 

[[7]] 
[[7]][[1]] 
[1] "K01623" "K01624" "K11645" 

[[7]][[2]] 
[1] "K03841" "K02446" "K11532" "K01086" "K04041" 
+0

Oh nette Funktion! aber es gibt immer noch 2 Probleme mit dem verschachtelten Teil. Der letzte Begriff fehlt "K01622" und ich hätte gerne Der Fall 3 ist so strukturiert, wie Sie sehen können, indem Sie den letzten Codeabschnitt ausführen, den ich in der Frage gepostet habe. –