web-dev-qa-db-fra.com

Supprimer la nouvelle ligne du fichier CSV

Je souhaite supprimer le nouveau caractère de ligne dans les données du champ de fichier CSV. La même question est posée par plusieurs personnes à SO/ailleurs. Cependant, les solutions fournies sont en script. Je cherche une solution dans des langages de programmation tels que PYTHON ou Spark (pas seulement ces deux-là), car j'ai de très gros fichiers.

Questions précédemment posées sur le même sujet:

J'ai un fichier CSV de taille ~ 1 Go et je veux supprimer les caractères de la nouvelle ligne dans les données du champ. Le schéma du fichier CSV varie de manière dynamique, je ne peux donc pas coder en dur le schéma. Le saut de ligne n'apparaît pas toujours avant une virgule, il apparaît au hasard, même dans un champ.

Exemple de données:

playerID,yearID,gameNum,gameName,teamName,lgID,GP,startingPos
gomezle01,1933,1,Cricket,Team1,NYA,AL,1
ferreri01,1933,2,Hockey,"This is 
Team2",BOS,AL,1
gehrilo01,1933,3,"Game name is 
Cricket" 
,Team3,NYA,AL,1
gehrich01,1933,4,Hockey,"Here it is 
Team4",DET,AL,1
dykesji01,1933,5,"Game name is 
Hockey"
,"Team name 
Team5",CHA,AL,1

Résultat attendu:

playerID,yearID,gameNum,gameName,teamName,lgID,GP,startingPos
gomezle01,1933,1,Cricket,Team1,NYA,AL,1
ferreri01,1933,2,Hockey,"This is Team2",BOS,AL,1
gehrilo01,1933,3,"Game name is Cricket" ,Team3,NYA,AL,1
gehrich01,1933,4,Hockey,"Here it is Team4",DET,AL,1
dykesji01,1933,5,"Game name is Hockey","Team name Team5",CHA,AL,1

Le caractère de nouvelle ligne peut figurer dans les données de tout champ.

Edit: Capture d’écran selon le code:

 enter image description here

4
user805

Si vous utilisez pyspark , je vous suggérerais alors d’utiliser la fonction wholeTextFiles de sparkContext / pour lire le fichier, puisque votre fichier doit être lu intégralement pour l’analyse de manière appropriée.

Après l'avoir lu à l'aide de wholeTextFiles, vous devez analyser en remplaçant les caractères de fin de ligne par et effectuer quelques mises en forme supplémentaires afin que le texte entier puisse être divisé en groupes de huit chaînes. 

import re
rdd = sc.wholeTextFiles("path to your csv file")\
    .map(lambda x: re.sub(r'(?!(([^"]*"){2})*[^"]*$),', ' ', x[1].replace("\r\n", ",").replace(",,", ",")).split(","))\
    .flatMap(lambda x: [x[k:k+8] for k in range(0, len(x), 8)])

Vous devriez obtenir une sortie en tant que 

[u'playerID', u'yearID', u'gameNum', u'gameName', u'teamName', u'lgID', u'GP', u'startingPos']
[u'gomezle01', u'1933', u'1', u'Cricket', u'Team1', u'NYA', u'AL', u'1']
[u'ferreri01', u'1933', u'2', u'Hockey', u'"This is Team2"', u'BOS', u'AL', u'1']
[u'gehrilo01', u'1933', u'3', u'"Game name is Cricket"', u'Team3', u'NYA', u'AL', u'1']
[u'gehrich01', u'1933', u'4', u'Hockey', u'"Here it is Team4"', u'DET', u'AL', u'1']
[u'dykesji01', u'1933', u'5', u'"Game name is Hockey"', u'"Team name Team5"', u'CHA', u'AL', u'1']

Si vous souhaitez convertir toutes les lignes du tableau rdd en chaînes de lignes, vous pouvez ajouter

.map(lambda x: ", ".join(x))

et vous devriez obtenir 

playerID, yearID, gameNum, gameName, teamName, lgID, GP, startingPos
gomezle01, 1933, 1, Cricket, Team1, NYA, AL, 1
ferreri01, 1933, 2, Hockey, "This is Team2", BOS, AL, 1
gehrilo01, 1933, 3, "Game name is Cricket", Team3, NYA, AL, 1
gehrich01, 1933, 4, Hockey, "Here it is Team4", DET, AL, 1
dykesji01, 1933, 5, "Game name is Hockey", "Team name Team5", CHA, AL, 1
2
Ramesh Maharjan

Vous pouvez utiliser les modules re, pandas et io comme suit:

import re
import io
import pandas as pd

with open('data.csv','r') as f:
    data = f.read()
df = pd.read_csv(io.StringIO(re.sub('"\s*\n','"',data)))

for col in df.columns: #To replace all line breaks in all textual columns
    if df[col].dtype == np.object_:
        df[col] = df[col].str.replace('\n','');

In [78]: df
Out[78]:
    playerID    yearID  gameNum gameName               teamName        lgID GP  startingPos
0   gomezle01   1933    1       Cricket                Team1           NYA  AL  1
1   ferreri01   1933    2       Hockey                 This is Team2   BOS  AL  1
2   gehrilo01   1933    3       Game name is Cricket   Team3           NYA  AL  1
3   gehrich01   1933    4       Hockey  Here it is     Team4           DET  AL  1
4   dykesji01   1933    5       Game name is Hockey    Team name Team5 CHA  AL  1

Si vous voulez que cette DataFrame en tant que fichier de sortie CSV, utilisez:

df.to_csv('./output.csv')
1
O.Suleiman

L'idée de base de cette solution est d'obtenir des morceaux de longueur fixe (de longueur égale au nombre de colonnes de la première ligne) en utilisant le grouper recipe . Comme il ne lit pas l'intégralité du fichier à la fois, l'utilisation de la mémoire par des fichiers volumineux ne serait pas augmentée.

$ cat a.py
import csv,itertools as it,operator as op

def grouper(iterable,n):return it.Zip_longest(*[iter(iterable)]*n)

with open('in.csv') as inf,open('out.csv','w',newline='') as outf:
 r,w=csv.reader(inf),csv.writer(outf)
 hdr=next(r)
 w.writerow(hdr)
 for row in grouper(filter(bool,map(op.methodcaller('replace','\n',''),it.chain.from_iterable(r))),len(hdr)):
  w.writerow(row)

$ python3 a.py
$ cat out.csv
playerID,yearID,gameNum,gameName,teamName,lgID,GP,startingPos
gomezle01,1933,1,Cricket,Team1,NYA,AL,1
ferreri01,1933,2,Hockey,This is Team2,BOS,AL,1
gehrilo01,1933,3,Game name is Cricket ,Team3,NYA,AL,1
gehrich01,1933,4,Hockey,Here it is Team4,DET,AL,1
dykesji01,1933,5,Game name is Hockey,Team name Team5,CHA,AL,1

Une hypothèse émise ici est l’absence de cellules vides dans l’entrée csv.

0
kpr

Celui-ci est basique avec un prétraitement simple avant de le lire via csv. 

import csv

def simple_sanitize(data):
    result = []
    for i, a in enumerate(data):
        if i + 1 != len(data) and data[i + 1][0] == ',':
            a = a.replace('\n', '')
            result.append(a + data[i + 1])
        Elif a[0] != ',':
            result.append(a)
    return result

data = [line for line in open('test.csv', 'r')]
sdata = simple_sanitize(data)

with open('out.csv','w') as f:
    for row in sdata:
        f.write(row)

result = [list(val.replace('\n', '') for val in line) for line in csv.reader(open('out.csv', 'r'))]

print(result)

Résultat :

[['playerID', 'yearID', 'gameNum', 'gameName', 'teamName', 'lgID', 'GP', 'startingPos'], 
['gomezle01', '1933', '1', 'Cricket', 'Team1', 'NYA', 'AL', '1'], 
['ferreri01', '1933', '2', 'Hockey', 'This is Team2', 'BOS', 'AL', '1'], 
['gehrilo01', '1933', '3', 'Game name is Cricket ', 'Team3', 'NYA', 'AL', '1'], 
['gehrich01', '1933', '4', 'Hockey', 'Here it is Team4', 'DET', 'AL', '1'], 
['dykesji01', '1933', '5', 'Game name is Hockey', 'Team name Team5', 'CHA', 'AL', '1']]
0
Reck

Il pourrait utiliser un peu de nettoyage, mais voici un code qui ferait ce que vous voulez. Fonctionne pour les sauts de ligne dans un champ et avant une virgule. Si davantage d'exigences sont nécessaires, quelques ajustements pourraient être effectués:

import csv

with open('data.csv', 'r') as csvfile:
    reader = csv.reader(csvfile, delimiter=',', quotechar='"')
    actual_rows = [next(reader)]
    length = len(actual_rows[0])
    real_row = []
    for row in reader:
        if len(row) < length:
            if real_row:
                real_row[-1] += row[0]
                real_row += row[1:]
            else:
                real_row = row
        else:
            real_row = row
        if len(real_row) == length:
            real_row = map(lambda s: s.replace('\n', ' '), real_row)
            # store real_row or use it as needed
            actual_rows.append(list(real_row))
            real_row = []

    print(actual_rows)

Je stocke les lignes corrigées dans actual_rows, mais si vous ne voulez pas charger en mémoire, utilisez simplement la variable real_row dans chaque boucle indiquée dans le commentaire.

0
damores