3 votes

Séparer avec une virgule spécifique et non entre guillemets en python

J'ai cette chaîne de caractères et je veux la diviser par des ",".

x = 'a, b, c , d , "x,x,2" , hi'
x.split(',')

Voici ma vraie chaîne

x = 'Outward   ,Supply , ,Tax Invoice ,IN9195212470,31/12/2019,VPS AGRO & AUTO PVT LTD ,311954,06AAACV9344F1ZA ,"VILLAGE KHANPUR KOLIAN, N.H. 1 ",6 K.M. FRO,KURUKSHETRA   ,HARYANA ,136131,VPS AGRO & AUTO PVT LTD ,311954,"VILLAGE KHANPUR KOLIAN, N.H. 1",6 K.M. FRO,KURUKSHETRA                             ,HARYANA             ,136131,503675,SM VAL. GENUINE DIESEL ENG. OIL 1/9 L   ,27101980,360,LTR,58204.04,9,5238.36,9,5238.36,0,0,0,0,0,0,0,68680.76,                    ,                    ,                              ,          ,          ,,               ,          ,06AAACW0287A1ZR   ,VALVOLINE CUMMINS PVT LTD-AMBALA        ,"KHASHRA NO-108/1/2,                                         ",          ,AMBALA                                  ,133004,HARYANA             ,                    ,                  ,                              , ,'

il renvoie le résultat suivant

['a','b','c','d','"x','x','2', 'hi']

Mais je veux avoir celui-ci

['a', 'b', 'c' , 'd' , '"x,x,2"' , 'hi']

comment faire cela en python

Aidez-moi

3voto

ababak Points 844
import shlex
lexer = shlex.shlex('a, b, c , d , "x,x,2" , hi')
lexer.whitespace += ','
print(list(lexer))

Résultat :

['a', 'b', 'c', 'd', '"x,x,2"', 'hi']

Voici une solution mise à jour pour une tâche actualisée :

x = 'Outward   ,Supply , ,Tax Invoice ,IN9195212470,31/12/2019,VPS AGRO & AUTO PVT LTD ,311954,06AAACV9344F1ZA ,"VILLAGE KHANPUR KOLIAN, N.H. 1 ",6 K.M. FRO,KURUKSHETRA   ,HARYANA ,136131,VPS AGRO & AUTO PVT LTD ,311954,"VILLAGE KHANPUR KOLIAN, N.H. 1",6 K.M. FRO,KURUKSHETRA                             ,HARYANA             ,136131,503675,SM VAL. GENUINE DIESEL ENG. OIL 1/9 L   ,27101980,360,LTR,58204.04,9,5238.36,9,5238.36,0,0,0,0,0,0,0,68680.76,                    ,                    ,                              ,          ,          ,,               ,          ,06AAACW0287A1ZR   ,VALVOLINE CUMMINS PVT LTD-AMBALA        ,"KHASHRA NO-108/1/2,                                         ",          ,AMBALA                                  ,133004,HARYANA             ,                    ,                  ,                              , ,'

import shlex
lexer = shlex.shlex(x)
lexer.whitespace = ','
lexer.whitespace_split = True
print([cell.strip() for cell in lexer])

Résultat :

['Outward', 'Supply', '', 'Tax Invoice', 'IN9195212470', '31/12/2019', 'VPS AGRO & AUTO PVT LTD', '311954', '06AAACV9344F1ZA', '"VILLAGE KHANPUR KOLIAN, N.H. 1 "', '6 K.M. FRO', 'KURUKSHETRA', 'HARYANA', '136131', 'VPS AGRO & AUTO PVT LTD', '311954', '"VILLAGE KHANPUR KOLIAN, N.H. 1"', '6 K.M. FRO', 'KURUKSHETRA', 'HARYANA', '136131', '503675', 'SM VAL. GENUINE DIESEL ENG. OIL 1/9 L', '27101980', '360', 'LTR', '58204.04', '9', '5238.36', '9', '5238.36', '0', '0', '0', '0', '0', '0', '0', '68680.76', '', '', '', '', '', '', '', '06AAACW0287A1ZR', 'VALVOLINE CUMMINS PVT LTD-AMBALA', '"KHASHRA NO-108/1/2,                                         "', '', 'AMBALA', '133004', 'HARYANA', '', '', '', '']

1voto

Jean-François Fabre Points 94672

Il n'existe pas de modules intégrés qui permettent d'atteindre cet objectif sans avoir recours à de nombreuses manipulations pour pré/post-traiter les données.

  • shlex.split fonctionnerait dans une certaine mesure avec cet exemple, mais c'est une tricherie, puisqu'il sépare les espaces. Si 2 éléments sont assemblés avec seulement des virgules, cela échouera.
  • ast.literal_eval ne fonctionnera pas car ... certains éléments ne sont pas des littéraux
  • csv.reader objet presque fait l'affaire avec [x.strip() for x in next(csv.reader([x]))] mais les guillemets ne sont pas traités correctement parce qu'il y a des espaces entre eux et les virgules.

Mais il est possible de passer en boucle sur chaque caractère à l'aide d'une simple machine à états :

x = 'a, b, c , d , "x,x,2" , hi'

in_quote = False
current = []
output = []
for c in x:
    if in_quote:
        current.append(c)
        if c=='"':
            output.append("".join(current))
            current = []
            in_quote = False
        continue

    if c==",":
        output.append("".join(current))
        current = []
    elif c==" ":
        pass
    else:
        current.append(c)
        if c=='"':
            in_quote = True

output.append("".join(current))

résultat :

['a', 'b', 'c', 'd', '"x,x,2"', '', 'hi']

Il suffit de sauter les espaces, de créer un nouvel élément en cas de virgule, mais d'avoir un indicateur en cas de guillemets.

Enfin, il ne faut pas oublier le dernier élément qui est accumulé lorsque la fin de la chaîne est rencontrée.

1voto

B.C Points 74

Une solution utilisant uniquement split . Veuillez noter qu'il utilise des chaînes f (python 3.6+) mais le même comportement peut être obtenu dans des versions plus anciennes. Il est possible de réaliser ceci sans utiliser de regex comme suit : Je vais commenter le code pour l'expliquer :

# First split by double quote
x = x.split('"')
final_x = []
for i in range(len(x)):
    # We know that if the list element is even then it must be outside double quotes
    if i%2 == 0:
        # Split the list by commas and strip any whitespace
        x_element = x[i].split(',')
        x_element = [el.strip() for el in x_element]
        # extend the list
        final_x.extend(x_element)
    else:
        # This is an odd element of the list, therefore inside quotation.
        # put the string back into quotations
        x_element = f'"{x[i]}"'
        #append this to the final list
        final_x.append(x_element)
# filter out any white spaces left from the various splits         
final_x = [el for el in final_x if el !=''] 

Notez la différence entre l'ajout des éléments impairs de la liste et l'extension des éléments pairs. En effet, vous créez une nouvelle liste avec la division et nous voulons étendre notre sortie, tandis que pour les éléments impairs, nous voulons ajouter un nouvel élément à la liste, d'où l'ajout d'un appendice.

1voto

Jan Points 370

Vous pouvez utiliser une approche par expressions rationnelles :

import regex as re

x = 'a, b, c , d , "x,x,2" , hi'

rx = re.compile(
    r"""
    "[^"]*"(*SKIP)(*FAIL)
    |
    \s*,\s*
    """, re.VERBOSE)
lst = rx.split(x)
print(lst)

On obtient ainsi

['a', 'b', 'c', 'd', '"x,x,2"', 'hi']

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X