1
votes

Supprimer les sauts de ligne en fonction du délimiteur

J'ai un fichier délimité | désordonné que je veux nettoyer. Une bonne ligne ressemble à ceci:

 data <- read_delim("myfile.txt", delim = "|")
 data <- data[, c(-1, -3, -5)] #to remove the columns just containing commas

Et plusieurs lignes en désordre qui ont des sauts de ligne là où ils n'appartiennent pas

 10,|some data|,|lots of text blah
 blah blah blah
 and more text
 sometimes text stretches across many lines|,|some numbers|

Comme indiqué, le le nombre de colonnes est théoriquement le même mais les données sont désordonnées de telle sorte qu'il y a des sauts de ligne là où ils ne devraient pas être.

Je voudrais lire dans le fichier afin que les valeurs entre | sont tous stockés dans le même vecteur (dans un dataframe).

Je lis actuellement dans le fichier en utilisant

 1,|some data|,|more data|,|some numbers|

Mais cela me donne beaucoup de mal lignes analysées.

Je pensais dire à R d'une manière ou d'une autre que je voudrais supprimer tous les sauts de ligne avant le 6ème |. Des idées sur la façon de faire cela ou comment lire dans ce fichier désordonné d'une autre manière?

Je dois ajouter que le fichier est très volumineux et que le rangement manuel n'est pas une option.

p>

r

2 commentaires

De quelle taille parle-t-on? Pouvez-vous lire tout le texte puis effectuer un remplacement de texte, ou est-ce trop volumineux? par exemple. txt <- paste (readLines ("filename.txt", collapse = "\ n"); read.table (text = gsub ("[^ |] \ n", "", txt), sep = " | ")


Le fichier fait environ 500 Mo ou environ 3,2 millions de lignes (y compris les lignes en désordre).


3 Réponses :


1
votes

Vos données semblent suivre quelques modèles:

  1. Les séparateurs de colonnes sont soit , | ou |,|
  2. Les séparateurs de ligne sont | \ n (barre suivie d'une nouvelle ligne)
  3. \ n peut apparaître aléatoirement au milieu de la colonne

Si vous pouvez identifier de tels modèles, vous pouvez traiter le fichier étape par étape afin de le faire passer au format csv le plus courant:

  V1        V2                                                                                        V3           V4
1  1 some data                                                                                 more data some numbers
2 10 some data lots of text blah blah blah blah and more text sometimes text stretches across many lines some numbers
3 10 some data lots of text blah blah blah blah and more text sometimes text stretches across many lines some numbers
4  1 some data                                                                                 more data some numbers

En utilisant ce pipeline, nous pouvons passer d'un fichier qui ressemble à ceci:

1,|some data|,|more data|,|some numbers|
10,|some data|,|lots of text blah
 blah blah blah
 and more text
 sometimes text stretches across many lines|,|some numbers|
10,|some data|,|lots of text blah
 blah blah blah
 and more text
 sometimes text stretches across many lines|,|some numbers|
1,|some data|,|more data|,|some numbers|

Vers le bloc de données suivant:

library(dplyr)

data <- readr::read_file("file.txt") %>%   # read the file as a string
  str_replace_all(",\\||\\|,\\|", ",") %>% # replace all column separators with commas
  str_replace_all("\n", "") %>%            # replace all newlines with empty strings
  str_replace_all("\\|", "\n") %>%         # replace all remaining bars with newlines
  read.csv(text = ., header = FALSE)       # read the .csv string into a data frame


2 commentaires

read_delim ("file.txt", delim = ",", quote = "|", col_names = F) fonctionnerait-il également? Je viens de lire quelque part que c'est une façon de lire ces fichiers.


@TeaTree ouais, ça semble marcher! Quelle solution magnifiquement concise.



1
votes

En suivant l'idée de @ thelatemale, nous pourrions utiliser readLines et réduire en une seule chaîne en utilisant paste .

Ensuite, nous appliquons strsplit deux fois . Tout d'abord, diviser la chaîne à ses numéros de ligne (ils se perdent mais je suppose qu'ils sont consécutifs). Deuxièmement, divisez les chaînes de la liste en |, | et nettoyez un peu en utilisant trinws . Enfin, rbind la chose.

1,|some data|,|more data|,|some numbers|
2,|some data|,|more data|,|some numbers|
3,|some data|,|more data|,|some numbers|
4,|some data|,|lots of text blah
blah blah blah
and more text
sometimes text stretches across many lines|,|some numbers|
5,|some data|,|more data|,|some numbers|
6,|some data|,|lots of text blah
blah blah blah
and more text, this time with comma,
sometimes text stretches across many lines|,|some numbers|
7,|some data|,|more data|,|some numbers|
8,|some data|,|lots of text blah
blah blah blah
and more text
sometimes text stretches across many lines|,|some numbers|
9,|some data|,|more data|,|some numbers|
10,|some data|,|more data|,|some numbers|

Résultat

# res
#           V1                                                                                                               V2           V3
# 1  some data                                                                                                        more data some numbers
# 2  some data                                                                                                        more data some numbers
# 3  some data                                                                                                        more data some numbers
# 4  some data                        lots of text blah blah blah blah and more text sometimes text stretches across many lines some numbers
# 5  some data                                                                                                        more data some numbers
# 6  some data lots of text blah blah blah blah and more text, this time with comma, sometimes text stretches across many lines some numbers
# 7  some data                                                                                                        more data some numbers
# 8  some data                        lots of text blah blah blah blah and more text sometimes text stretches across many lines some numbers
# 9  some data                                                                                                        more data some numbers
# 10 some data                                                                                                        more data some numbers

messy.txt

txt <- paste(readLines(con="R/messy.txt"), collapse=" ")
rr <- el(strsplit(txt, "\\b\\d*\\,\\|"))[-1]
rr <- strsplit(trimws(rr, whitespace="[\\|| ]"), "|,|", fixed=TRUE)
res <- as.data.frame(do.call(rbind, rr))


0 commentaires

1
votes

La solution la plus simple semble être

# X1         X2                                                                                                               X3           X4
# 1  some data                                                                                                        more data some numbers
# 2  some data                        lots of text blah blah blah blah and more text sometimes text stretches across many lines some numbers

quote indique à read_delim le début et la fin du vecteur même lorsqu'il dépasse plusieurs lignes dans le fichier source. L'argument delim spécifie que les chaînes indiquées par | sont séparés par des virgules.

Cela fonctionne également avec read.delim

1,|some data|,|more data|,|some numbers|
2,|some data|,|lots of text blah
blah blah blah
and more text
sometimes text stretches across many lines|,|some numbers|

et avec data.table fread de / code> pour la vitesse maximale

library(data.table)
fread("file.txt", sep = ",", quote = "|",  header = F)

Données

file.txt

read.delim("file.txt", sep = ",", quote = "|",  header = F)

Résultat

library(readr)
read_delim("file.txt", delim = ",", quote = "|", col_names = F)

p >


1 commentaires

Cela fonctionne-t-il également avec l'ancien read.delim ?