83 votes

Est-il possible d'incrémenter des nombres à l'aide d'une substitution d'expressions rationnelles ?

Est-il possible d'incrémenter des nombres à l'aide d'une substitution d'expressions rationnelles ? Pas en utilisant substitution évaluée/fonctionnelle bien sûr.

Cette question a été inspirée par un autre, où le demandeur voulait incrémenter des nombres dans un éditeur de texte . Il y a probablement plus d'éditeurs de texte qui prennent en charge la substitution par des expressions rationnelles que d'éditeurs qui prennent en charge des scripts complets, de sorte qu'une expression rationnelle peut être pratique à utiliser, si elle existe.

Par ailleurs, j'ai souvent appris des choses intéressantes grâce à des solutions intelligentes à des problèmes pratiquement inutiles, alors je suis curieux.

Supposons que nous ne parlions que d'entiers décimaux non négatifs, c'est-à-dire \d+ .

  • Est-ce possible en une seule substitution ? Ou en un nombre fini de substitutions ?

  • Si ce n'est pas le cas, est-il au moins possible étant donné une borne supérieure par exemple, les chiffres jusqu'à 9999 ?

Bien sûr, c'est faisable avec une boucle while (en remplaçant while par matched), mais nous optons ici pour une solution sans boucle.

0voto

PM Hui Points 181

J'avais besoin d'incrémenter d'une unité les indices des fichiers de sortie d'un pipeline que je ne peux pas modifier. Après quelques recherches, je suis tombé sur cette page. Bien que les lectures soient significatives, elles ne donnent pas de solution lisible au problème. Oui, il est possible de le faire avec seulement des expressions rationnelles ; non, ce n'est pas aussi compréhensible.

J'aimerais ici donner une solution lisible en utilisant Python afin que d'autres n'aient pas à réinventer la roue. J'imagine que beaucoup d'entre vous ont abouti à une solution similaire.

L'idée est de diviser les noms de fichiers en trois groupes, et de formater votre chaîne de correspondance de manière à ce que l'index incrémenté corresponde au groupe du milieu. Il est alors possible de n'incrémenter que le groupe du milieu, après quoi nous reconstituons les trois groupes.

import re
import sys
import argparse
from os import listdir
from os.path import isfile, join

def main():
    parser = argparse.ArgumentParser(description='index shift of input')
    parser.add_argument('-r', '--regex', type=str,
            help='regex match string for the index to be shift')
    parser.add_argument('-i', '--indir', type=str,
            help='input directory')
    parser.add_argument('-o', '--outdir', type=str,
            help='output directory')

    args = parser.parse_args()
    # parse input regex string
    regex_str = args.regex
    regex = re.compile(regex_str)
    # target directories
    indir = args.indir
    outdir = args.outdir

    try:
        for input_fname in listdir(indir):
            input_fpath = join(indir, input_fname)
            if not isfile(input_fpath): # not a file
                continue

            matched = regex.match(input_fname)
            if matched is None: # not our target file
                continue
            # middle group is the index and we increment it
            index = int(matched.group(2)) + 1
            # reconstruct output
            output_fname = '{prev}{index}{after}'.format(**{
                'prev'  : matched.group(1),
                'index' : str(index),
                'after' : matched.group(3)
            })
            output_fpath = join(outdir, output_fname)

            # write the command required to stdout
            print('mv {i} {o}'.format(i=input_fpath, o=output_fpath))
    except BrokenPipeError:
        pass

if __name__ == '__main__': main()

J'ai ce script nommé index_shift.py . Pour donner un exemple d'utilisation, mes fichiers sont nommés k0_run0.csv pour des séries d'amorçage de modèles d'apprentissage automatique utilisant des paramètres k . Le paramètre k commence à zéro et la carte d'index souhaitée commence à un. Nous commençons par préparer les répertoires d'entrée et de sortie afin d'éviter d'écraser les fichiers

$ ls -1 test_in/ | head -n 5
k0_run0.csv
k0_run10.csv
k0_run11.csv
k0_run12.csv
k0_run13.csv
$ ls -1 test_out/

Pour voir comment fonctionne le script, il suffit d'imprimer sa sortie :

$ python3 -u index_shift.py -r '(^k)(\d+?)(_run.+)' -i test_in -o test_out | head -n5
mv test_in/k6_run26.csv test_out/k7_run26.csv
mv test_in/k25_run11.csv test_out/k26_run11.csv
mv test_in/k7_run14.csv test_out/k8_run14.csv
mv test_in/k4_run25.csv test_out/k5_run25.csv
mv test_in/k1_run28.csv test_out/k2_run28.csv

Il génère bash mv pour renommer les fichiers. Maintenant, nous envoyons les lignes directement dans bash .

$ python3 -u index_shift.py -r '(^k)(\d+?)(_run.+)' -i test_in -o test_out | bash

En vérifiant la sortie, nous avons réussi à décaler l'index d'une unité.

$ ls test_out/k0_run0.csv
ls: cannot access 'test_out/k0_run0.csv': No such file or directory
$ ls test_out/k1_run0.csv
test_out/k1_run0.csv

Vous pouvez également utiliser cp au lieu de mv . Mes fichiers sont assez gros, je voulais donc éviter de les dupliquer. Vous pouvez aussi refactoriser le nombre de fichiers que vous déplacez en tant qu'argument d'entrée. Je n'ai pas pris la peine de le faire, car le décalage par un est la plupart de mes cas d'utilisation.

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