Partage
  • Partager sur Facebook
  • Partager sur Twitter

modifier le comportement de range()

    19 janvier 2021 à 17:18:40

    Bonjour,

    Je cherche a créer un générateur qui découpe une string une fois en un morceau de 8 caractères et ensuite en morceaux de 16 jusqu'à la fin de la ligne.

    J'ai ça, mais le problème c'est qu'il faudrait que je change l'argument du pas de range après la première itération du générateur. Je maitrise pas trop les générateurs du coup je bug un peu sur comment régler mon soucis.

    def chunk_long(line):
    	"""Générateur qui split une line tout les 16 caractères après avoir splitté une fois après 8 char """
    	
    	for start in range(0, len(line), 8): # après la première itération j'aimerai que l'argument 8 de range devienne 16
    		if start == 0:
    			yield line[start:start+8]
    		else:
    			yield line[start:start+16]

    J'imagine que je pourrais régler mon soucis en créant un générateur perso pour remplacer range() mais il y a peut être une solution plus simple que je ne vois pas.


    Merci de votre aide

    -
    Edité par Jojuss 19 janvier 2021 à 17:21:08

    • Partager sur Facebook
    • Partager sur Twitter
      19 janvier 2021 à 17:49:10

      Oui, il y a beaucoup plus simple : tu split une fois sur 8 caractères avant la boucle, et tu fais ta boucle sur 16 ensuite.
      • Partager sur Facebook
      • Partager sur Twitter

      Blond, bouclé, toujours le sourire aux lèvres...

        19 janvier 2021 à 19:09:51

        Par exemple:
        s="012345670123456789abcdef0123456789abcdefghj"
        a, b = s[:8], s[8:]
        L=[a]+[b[i:i+16] for i in range(0, len(b), 16)]
        print(L)
        Ce qui donne:
        ['01234567', '0123456789abcdef', '0123456789abcdef', 'ghj']
        • Partager sur Facebook
        • Partager sur Twitter

        Le Tout est souvent plus grand que la somme de ses parties.

          19 janvier 2021 à 20:24:58

          def chunk_long(s):
              for i in range(-8, len(s), 16):
                  yield s[i:i+16] or s[:8]
          
          
          s = 'azertyuiopqsdfghjklmwxcvbn'
          for i in chunk_long(s):
              print(i)
          azertyui
          opqsdfghjklmwxcv
          bn
          


          -
          Edité par josmiley 19 janvier 2021 à 20:34:21

          • Partager sur Facebook
          • Partager sur Twitter

          Python c'est bon, mangez-en. 

            20 janvier 2021 à 7:12:55

            Je ne sais pas si Jojuss veut absolument un générateur ou simplement découper sa ligne.
            Ça se fait facilement avec une compréhension, dans le même style que le code de josmiley:
            s="012345670123456789abcdef0123456789abcdefghj"
            L=[s[i:i+16] or s[:8] for i in range(-8, len(s), 16)]
            print(L)
            • Partager sur Facebook
            • Partager sur Twitter

            Le Tout est souvent plus grand que la somme de ses parties.

              20 janvier 2021 à 8:24:11

              Ma petite participation,

              from textwrap import wrap
              
              s = "012345670123456789abcdef0123456789abcdefghj"
              
              res = [s[:8]] + wrap(s[8:], 16)
              
              print('\n'.join(res))



              • 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 janvier 2021 à 9:28:12

                @LoupSolitaire : Bah oui ... la fatigue de fin de soirée, nous fait oublier nos basiques :D

                Pour les autres, pour rester consistant avec le reste de mon code, je préfère utiliser un générateur pour faire ceci.

                Du coup le code de josmiley me convient parfaitement, par contre je n'arrive pas trop à comprendre pourquoi il faut rajouter le  or s[:8] .

                Si i = -8 on a s[-8:8] qui retourne déjà les 8 premiers caractères ?

                • Partager sur Facebook
                • Partager sur Twitter
                  20 janvier 2021 à 10:43:54

                  en fait mon code n'est pas bon car il ne fonctionne que pour les chaines d'au moins 16 caractères.
                  • Partager sur Facebook
                  • Partager sur Twitter

                  Python c'est bon, mangez-en. 

                    20 janvier 2021 à 16:58:35

                    en partant de ton code et faisant une autre boucle for + yield dans le else (j'ai laissé les print de debug):

                    def chunk_long(line):
                        """Générateur qui split une line tout les 16 caractères après avoir splitté une fois après 8 char """
                        pas=8
                        for start in range(0, len(line), pas): # après la première itération j'aimerai que l'argument 8 de range devienne 16
                            print("start:",start)
                            if start == 0:
                                print("pas:",pas)
                                yield line[start:start+pas]
                            else:
                                pas=16
                                for start in range(start,len(line),pas):
                                    print("start:",start)
                                    yield line[start:start+pas]
                                break
                    
                    s = 'azertyuiopqsdfghjklmwxcvbn012345679AZERRTYUIOP'
                    for i in chunk_long(s):
                        print(i)
                    



                    • Partager sur Facebook
                    • Partager sur Twitter
                      20 janvier 2021 à 17:55:13

                      La raison pour laquelle josmiley met "or s[:8]" est que si le premier indice est négatif, s[-8: 8] donne une chaîne vide
                      On part de la fin - 8, donc 16-8 jusqu'à +8, ce qui donne bien une chaîne vide.
                      @umfred:
                      As-tu besoin de tester si start vaut 0 et mettre pas à 16 si c'est le cas?
                      Puisque le pas sera de 16 pour toujours après la première passe, mets le d'office à 16, sans test.
                      En fait, c'est le for qui bloque avec son range. Avec un while, ça marcherait.
                      Et tu n'aurais pas besoin de 2 boucles.
                      • Partager sur Facebook
                      • Partager sur Twitter

                      Le Tout est souvent plus grand que la somme de ses parties.

                        20 janvier 2021 à 18:20:46

                        PierrotLeFou a écrit:

                        La raison pour laquelle josmiley met "or s[:8]" est que si le premier indice est négatif, s[-8: 8] donne une chaîne vide
                        On part de la fin - 8, donc 16-8 jusqu'à +8, ce qui donne bien une chaîne vide.

                        ça dépend de la taille de la chaine.

                        après correction:

                        def chunk_long(s):
                            i = 0
                            for j in range(8, len(s)+16, 16):
                                yield s[i:j]
                                i = j



                        -
                        Edité par josmiley 20 janvier 2021 à 18:21:41

                        • Partager sur Facebook
                        • Partager sur Twitter

                        Python c'est bon, mangez-en. 

                          20 janvier 2021 à 18:52:11

                          @josmiley:
                          Je pense que c'est le plus court qu'on peut faire avec un générateur. Je l'ai testé avec toutes sortes de longueurs: 0, 4, 8, 9, 24, etc.
                          La solution de fred1599 est très bien mais, comme la mienne, ne comporte pas de générateur codé par l'utilisateur.
                          • Partager sur Facebook
                          • Partager sur Twitter

                          Le Tout est souvent plus grand que la somme de ses parties.

                            20 janvier 2021 à 19:27:00

                            PierrotLeFou a écrit:

                            @josmiley:
                            Je pense que c'est le plus court qu'on peut faire avec un générateur.

                            chunk_long = lambda s: (s[j+8 and j:j+16] for j in range(-8, len(s), 16))
                            
                            s = 'azertyuiopqsdfghjklmwxcvbn'
                            for i in chunk_long(s):
                                print(i)
                            
                            


                            -
                            Edité par josmiley 20 janvier 2021 à 19:29:52

                            • Partager sur Facebook
                            • Partager sur Twitter

                            Python c'est bon, mangez-en. 

                              21 janvier 2021 à 2:06:50

                              Ça prenait josmiley pour battre josmiley. :)
                              • Partager sur Facebook
                              • Partager sur Twitter

                              Le Tout est souvent plus grand que la somme de ses parties.

                                21 janvier 2021 à 8:28:17

                                Après un gros dodo j'ai les idées plus claires, donc je finirai avec:

                                chunk_long = lambda s: (s[j-len(s):j+16] for j in range(-8, len(s), 16))

                                slicing plus naturel, pas de 'and' au milieu pour cacher un teste de nullité, du pur slicing ... 

                                -
                                Edité par josmiley 21 janvier 2021 à 8:39:57

                                • Partager sur Facebook
                                • Partager sur Twitter

                                Python c'est bon, mangez-en. 

                                  21 janvier 2021 à 9:21:11

                                  J'ai au final opté pour la solution de LoupSolitaire, c'est pas beaucoup plus long et plus compréhensible que d'essayer de tout caler d'un coup. Ceci dit toutes les solutions proposées sont intéressantes, toujours sympa de voir comment chacun trouve une solution différente à un problème commun.
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    21 janvier 2021 à 10:03:12

                                    Jojuss a écrit:

                                    J'ai au final opté pour la solution de LoupSolitaire, c'est pas beaucoup plus long et plus compréhensible que d'essayer de tout caler d'un coup. Ceci dit toutes les solutions proposées sont intéressantes, toujours sympa de voir comment chacun trouve une solution différente à un problème commun.


                                    si t'es pas à l'aise avec les lambda, en version classique ça donne ça:

                                    def chunk_long(s):
                                        for j in range(-8, len(s), 16):
                                            yield s[j-len(s):j+16]



                                    • Partager sur Facebook
                                    • Partager sur Twitter

                                    Python c'est bon, mangez-en. 

                                    modifier le comportement de range()

                                    × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                    × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                    • Editeur
                                    • Markdown