Partage
  • Partager sur Facebook
  • Partager sur Twitter

Spliter tous les 3 charactères (charactère défini)

Sujet résolu
10 mars 2019 à 21:27:02

Bonjour,

Je souhaite splitter une chaîne tous les 3 \0.

Un exemple sera peut-être plus parlant :

>>>fonction("a\0b\0c\0d\0e\0f")
["a\0b\0c", "d\0e\0f"]

Reste à déterminer quelle fonction permet de faire ceci.

Merci d'avance de votre aide

  • Partager sur Facebook
  • Partager sur Twitter
"La théorie, c'est quand on sait tout et que rien ne fonctionne.La pratique, c'est quand tout fonctionne et que personne ne sait pourquoi.Ici, nous avons réuni théorie et pratique: Rien ne fonctionne... et personne ne sait pourquoi !"Albert Einstein
10 mars 2019 à 21:44:26

Je ne suis pas sûr qu'une fonction pour faire ça existe, mais tu peux la créer, ce n'est pas très compliqué

  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2019 à 22:03:08

Salut, tu peux essayer quelque chose comme ça :

def split(string, sep, n):
    ret=[]
    l=string.split(sep)
    for i in range(0, len(l), n):
            ret.append(sep.join(l[i:i+n]))
    return ret


C'est sale mais ça fait le travail

-
Edité par __Nicolas__ 10 mars 2019 à 22:03:39

  • Partager sur Facebook
  • Partager sur Twitter
10 mars 2019 à 22:40:18

Nicolas a écrit: > C'est sale mais ça fait le travail

L'objectif, ça reste que ça soit optimisée, et je pense que ça l'est. Et puis au pire ce n'est pas le genre de fonction qui a besoin d'être relue...

  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
10 mars 2019 à 22:57:13

def funct(s)
    ls, k, n = [], 0, 3
    for i, c in enumerate(s):
        if c == '\0':
            n -= 1
        if not n:
            ls.append(s[k:i])
            k, n = i + 1, 3
    if k < i:
        ls.append(s[k:])
    return ls
  • Partager sur Facebook
  • Partager sur Twitter
11 mars 2019 à 14:01:32

Ou avec regex :

import re


def split(string, size):
    return re.findall(".{1,%d}" % size, string)


Ou avec itertools, ce dernier est le plus optimisé, mais attention ça ne renvoie pas une liste de chaînes mais un générateur de tuples.

from itertools import zip_longest


def split(iterable, n, fillvalue=""):
    args = [iter(iterable)] * n
    return zip_longest(*args, fillvalue=fillvalue)


Donc ça dépend de ton algo, si tu as besoin obligatoirement d'une liste de chaînes utilise plutôt la solution avec regex, ça sera plus rapide que de prendre celle avec itertools et de faire un join sur chaque tuple.

-
Edité par thelinekioubeur 11 mars 2019 à 14:23:09

  • Partager sur Facebook
  • Partager sur Twitter
11 mars 2019 à 17:51:12

Je vais opter pour la solution avec regex je vais tester ce soir.

Merci à tous pour vos réponses !

----- EDIT -----

Voici ce que j'obtiens :

>>> split("a\0b\0c\0d\0e\0f", 6)
['a\x00b\x00c\x00', 'd\x00e\x00f']

Serait-il possible de supprimer le dernier "\x00" du premier élément de la liste ? De sorte à obtenir quelque chose comme ceci :

>>> split("a\0b\0c\0d\0e\0f", 6)
['a\x00b\x00c', 'd\x00e\x00f']

En modifiant le regex ou sans faire une boucle for (ce qui prendrait beaucoup de temps vu la taille de la chaîne à traiter).

----- EDIT 2 -----

De plus, ceci ne fonctionne pas si la chaîne comprise entre deux "\x00" n'est pas de longueur 1.

-
Edité par Dev0110 11 mars 2019 à 19:19:12

  • Partager sur Facebook
  • Partager sur Twitter
"La théorie, c'est quand on sait tout et que rien ne fonctionne.La pratique, c'est quand tout fonctionne et que personne ne sait pourquoi.Ici, nous avons réuni théorie et pratique: Rien ne fonctionne... et personne ne sait pourquoi !"Albert Einstein
11 mars 2019 à 19:44:39

La vraie question c'est pourquoi tu as ça plutôt que "abcdef" ?

Mais sinon c'est possible sans boucle avec la méthode str.replace ou re.sub.

Je ne sais pas si c'est possible juste en modifiant la regex.

-
Edité par thelinekioubeur 11 mars 2019 à 20:02:20

  • Partager sur Facebook
  • Partager sur Twitter
11 mars 2019 à 20:20:36

"abcdef" n'est qu'un exemple. J'aimerais pouvoir splitter des chaines de caractères délimités par des \0 mais uniquement toutes les 3 occurrences de ce caractère.
  • Partager sur Facebook
  • Partager sur Twitter
"La théorie, c'est quand on sait tout et que rien ne fonctionne.La pratique, c'est quand tout fonctionne et que personne ne sait pourquoi.Ici, nous avons réuni théorie et pratique: Rien ne fonctionne... et personne ne sait pourquoi !"Albert Einstein
11 mars 2019 à 20:39:52

Dev0110 a écrit:

"abcdef" n'est qu'un exemple. J'aimerais pouvoir splitter des chaines de caractères délimités par des \0 mais uniquement toutes les 3 occurrences de ce caractère.


Je suis d'accord avec thelinekioubeur , je me demande comment ont été implantés ces '\x00'.

Si c'est fait via un code, alors je ne comprend pas pourquoi cette stratégie du split n'est pas appliquée à la volée, plutôt que d'y ajouter ce caractère et retravailler par la suite, de nouveau sur l'ensemble du texte.

  • Partager sur Facebook
  • Partager sur Twitter

Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

11 mars 2019 à 21:07:52

Beh si tu fais string.replace("\0", "") ça vire tout les \0...

Après tu split sur le résultat.

  • Partager sur Facebook
  • Partager sur Twitter
11 mars 2019 à 21:32:43

Mon problème n'est pas le caractère \0 mais d'arriver à ce résultat :

Sachant que entre les 2 lignes il y encore un \0 avant application de la fonction.

Le but est de splitter cette chaîne uniquement si l’occurrence du \0 est un multiple de trois.

Les codes indiqués par IdiotBête_ et __Nicolas_ donnent le résultat attendu :

>>> split("a\0b\0c\0d\0e\0f", "\0", 3)
['a\x00b\x00c', 'd\x00e\x00f']
>>> funct("a\0b\0c\0d\0e\0f")
['a\x00b\x00c', 'd\x00e\x00f']



-
Edité par Dev0110 11 mars 2019 à 21:36:18

  • Partager sur Facebook
  • Partager sur Twitter
"La théorie, c'est quand on sait tout et que rien ne fonctionne.La pratique, c'est quand tout fonctionne et que personne ne sait pourquoi.Ici, nous avons réuni théorie et pratique: Rien ne fonctionne... et personne ne sait pourquoi !"Albert Einstein
11 mars 2019 à 22:45:22

Mon problème n'est pas le caractère \0

Si c'est toi qui les a ajouté si, c'est un gros problème sur le concept. Parce-que je ne vois pas en quoi ajouter une chaîne '\x00' serait mieux que d'ajouter chemin par chemin dans une liste par exemple...

Si c'est un logiciel qui génère ce type de format (ce qui m'étonne beaucoup) alors c'est un logiciel bon à mettre à la benne :D

  • Partager sur Facebook
  • Partager sur Twitter

Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

Anonyme
12 mars 2019 à 2:22:16

with open(".../old.dat", "rb") as old, open(".../new.dat", "wb") as new:
    args = [iter(old.read().split(b"\x00"))] * 3
    new.write(b"\n".join(b"\x00".join(row) for row in zip(*args)))
  • Partager sur Facebook
  • Partager sur Twitter
19 mars 2019 à 17:32:14

Excusez-moi pour ma réponse tardive.

fred1599 a écrit:

Mon problème n'est pas le caractère \0

Si c'est toi qui les a ajouté si, c'est un gros problème sur le concept. Parce-que je ne vois pas en quoi ajouter une chaîne '\x00' serait mieux que d'ajouter chemin par chemin dans une liste par exemple...

Si c'est un logiciel qui génère ce type de format (ce qui m'étonne beaucoup) alors c'est un logiciel bon à mettre à la benne :D


C'est moi qui ajoute ces \0 car c'est le seul caractère qui n'est utilisé par aucun système d'exploitation pour nommer un fichier ou un dossier.

Sinon laquelle des 3 propositions (les 2 de IdiotBête_ et celle de __Nicolas_) est la plus rapide à exécuter ou la plus pythonique ?

Merci pour vos réponses

  • Partager sur Facebook
  • Partager sur Twitter
"La théorie, c'est quand on sait tout et que rien ne fonctionne.La pratique, c'est quand tout fonctionne et que personne ne sait pourquoi.Ici, nous avons réuni théorie et pratique: Rien ne fonctionne... et personne ne sait pourquoi !"Albert Einstein
19 mars 2019 à 19:09:36

Ce n'est pas compliqué de tester par toi même la différence de perfs.
  • Partager sur Facebook
  • Partager sur Twitter
19 mars 2019 à 21:11:55

Dev0110 a écrit:

fred1599 a écrit:

Mon problème n'est pas le caractère \0

Si c'est toi qui les a ajouté si, c'est un gros problème sur le concept. Parce-que je ne vois pas en quoi ajouter une chaîne '\x00' serait mieux que d'ajouter chemin par chemin dans une liste par exemple...

Si c'est un logiciel qui génère ce type de format (ce qui m'étonne beaucoup) alors c'est un logiciel bon à mettre à la benne :D


C'est moi qui ajoute ces \0 car c'est le seul caractère qui n'est utilisé par aucun système d'exploitation pour nommer un fichier ou un dossier.

Pourquoi ne pas utiliser le caractère \n dans ce cas ?

  • Partager sur Facebook
  • Partager sur Twitter

Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

Anonyme
19 mars 2019 à 21:42:54

> C'est moi qui ajoute ces \0 car c'est le seul caractère qui n'est utilisé par aucun système d'exploitation pour nommer un fichier ou un dossier.

Il existe de nombreux caractères qui ne sont pas autorisé dans des noms de fichiers dont des symboles et des ponctuations.

Je précise au cas où, et c'est aussi pour ça que j'ouvre le fichier en mode binaire et que je manipule des bytes dans mon second exemple, \x00 n'est pas un caractère, c'est la représentation d'un octet (byte), en l’occurrence un octet ayant la valeur 0.

Aussi, c'est à l'origine qu'il faut formater correctement le fichier. Convertir le fichier comme on le fait ici ne sert à rien si tu es en mesure, dès le départ, de produire un fichier correct.

  • Partager sur Facebook
  • Partager sur Twitter
19 mars 2019 à 23:00:23

Idiotbête : \0 en python représente le caractère NUL, qui est représenté par l'octet zéro dans la plupart des encoding.

Dev0110 : Mais perso je n'ai toujours pas compris pourquoi tu mets des \0.

-
Edité par thelinekioubeur 19 mars 2019 à 23:02:33

  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
19 mars 2019 à 23:30:52

C'est un caractère de contrôle, effectivement. Et ce n'est pas non-plus illogique de le voir ici pour signifier la fin d'une entrée.

Personnellement j'aurais formaté le fichier d'origine différemment, type CSV. Pour séparer les colonnes, des barres verticales ou des points-virgules, et pour séparer les lignes... des fins de ligne.

  • Partager sur Facebook
  • Partager sur Twitter
20 mars 2019 à 21:04:50

Sur Linux, n'importe quel caractère sauf le NULL peut être utilisé pour nommer un dossier ou un fichier. Le caractère NULL ("\0") est donc une valeur sûre pour délimiter les champs.

Je pense qu'un CSV serait plus lourd qu'un fichier texte formaté avec ce caractère.

thelinekioubeur a écrit:

Ce n'est pas compliqué de tester par toi même la différence de perfs.

Comment le faire sachant que les temps d'éxécution sont de l'ordre de la milliseconde (pas mesurable pour un humain)?

  • Partager sur Facebook
  • Partager sur Twitter
"La théorie, c'est quand on sait tout et que rien ne fonctionne.La pratique, c'est quand tout fonctionne et que personne ne sait pourquoi.Ici, nous avons réuni théorie et pratique: Rien ne fonctionne... et personne ne sait pourquoi !"Albert Einstein
20 mars 2019 à 21:52:06

Tu répète l'algo 100000 fois dans une boucle, et tu mesures avec time ou datetime.

Allez cadeau j'ai un context manager sous la main :

from datetime import datetime


class TimeIt:
    def __enter__(self):
        self.start = datetime.now()
        print(self.start)

    def __exit__(self, type, value, traceback):
        print("%s seconds" % (datetime.now() - self.start).total_seconds())

Utilisation :

with TimeIt():
    for _ in range(100000):
        fonction_a_mesurer()




-
Edité par thelinekioubeur 20 mars 2019 à 21:52:23

  • Partager sur Facebook
  • Partager sur Twitter
20 mars 2019 à 22:18:02

thelinekioubeur a écrit:

Tu répète l'algo 100000 fois dans une boucle, et tu mesures avec time ou datetime.

Allez cadeau j'ai un context manager sous la main :

from datetime import datetime


class TimeIt:
    def __enter__(self):
        self.start = datetime.now()
        print(self.start)

    def __exit__(self, type, value, traceback):
        print("%s seconds" % (datetime.now() - self.start).total_seconds())

Utilisation :

with TimeIt():
    for _ in range(100000):
        fonction_a_mesurer()




-
Edité par thelinekioubeur il y a moins de 30s


Super c'est extra !

Temps d'éxécution similaires donc ça ne m'avance pas trop :lol:

  • Partager sur Facebook
  • Partager sur Twitter
"La théorie, c'est quand on sait tout et que rien ne fonctionne.La pratique, c'est quand tout fonctionne et que personne ne sait pourquoi.Ici, nous avons réuni théorie et pratique: Rien ne fonctionne... et personne ne sait pourquoi !"Albert Einstein
20 mars 2019 à 22:31:15

Dev0110 a écrit:

Sur Linux, n'importe quel caractère sauf le NULL peut être utilisé pour nommer un dossier ou un fichier. Le caractère NULL ("\0") est donc une valeur sûre pour délimiter les champs.

Je pense qu'un CSV serait plus lourd qu'un fichier texte formaté avec ce caractère.

Vous pensez ?  En 15 ans c'est la première fois que j'entends cela, ça serait bien de vérifier ces affirmations, vous ne pensez pas ? 

  • Partager sur Facebook
  • Partager sur Twitter

Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

20 mars 2019 à 22:58:27

Le problème du CSV est que si quelqu'un nomme un dossier avec un ; ça va tout décaler non ?

  • Partager sur Facebook
  • Partager sur Twitter
"La théorie, c'est quand on sait tout et que rien ne fonctionne.La pratique, c'est quand tout fonctionne et que personne ne sait pourquoi.Ici, nous avons réuni théorie et pratique: Rien ne fonctionne... et personne ne sait pourquoi !"Albert Einstein
20 mars 2019 à 23:05:25

Nommer un dossier avec un  point virgule ?  Qui fait ça et surtout dans quel but ?  J'ai déjà vu les tirets hauts et bas, mais point virgule, jamais... Sinon le csv avec d'autres splitter est possible.

Pourquoi ne pas suivre tout simplement les standards ? 

  • Partager sur Facebook
  • Partager sur Twitter

Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

21 mars 2019 à 7:35:15

Je ne sais pas qui le ferait mais j essaye de prévenir toutes les possibilités. Un décalage dans le splittage serait très compliqué à gérer.
  • Partager sur Facebook
  • Partager sur Twitter
"La théorie, c'est quand on sait tout et que rien ne fonctionne.La pratique, c'est quand tout fonctionne et que personne ne sait pourquoi.Ici, nous avons réuni théorie et pratique: Rien ne fonctionne... et personne ne sait pourquoi !"Albert Einstein
21 mars 2019 à 7:44:55

On peut très bien mettre des ; dans les csv :

colonne1;colonne2
valeur;"valeur;avec;point;virgule"

Et puis on a le choix du délimiteur aussi.

  • Partager sur Facebook
  • Partager sur Twitter
21 mars 2019 à 7:55:14

Dev0110 a écrit:

Je ne sais pas qui le ferait mais j essaye de prévenir toutes les possibilités. Un décalage dans le splittage serait très compliqué à gérer.

Pourquoi dire "c'est compliqué" sans vous expliquer sur la difficulté, car je ne là vois pas me concernant, et pas sûr que les autres membres non plus.
  • Partager sur Facebook
  • Partager sur Twitter

Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

Anonyme
21 mars 2019 à 14:20:55

Utiliser le format CSV, et donc la bibliothèque CSV n'a que des avantage dans ton cas. Tu n'as même pas besoin de te soucier des paramètres delimiter, quotechar et autres. La bibliothèque gère tout ça sans problème. Lis la documentation, tu verras, c'est vraiment pratique. ;)

-
Edité par Anonyme 21 mars 2019 à 14:21:20

  • Partager sur Facebook
  • Partager sur Twitter