Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 17/09/2020, à 15:30

Julie M

[Résolu] Boucle remplacement de caractères et opérations

Bonjour à tous,

Tout d’abord je tiens à préciser que je suis totalement novice en shell. Je cherche à écrire un script me permettant de faire plusieurs modifications sur un gros fichier (15Go compressé)

Exemple de fichier :
1/1     0/1     0/0    1/0    1/1     1/1:0,0.003,0.997       1/1     1/1     1/1     1/1:0,0.042,0.958     1/1     1/1     1/1     1/1     1/1:0,0.001,0.999       1/1     1/1     1/1:0,0.00903,0.99097   1/1     1/1:0,0.042,0.958       1/1     

Je dois :
-    Remplacer les 1/1 par 2, les 0/1 et 1/0 par 1 et les 0/0 par 0
-    Lorsque le format est « 1/1:0,0.042,0.958» je dois effectuer une opération sur les 3 valeurs situées après « 1/1: » . A savoir :  1*première valeur + 1*deuxième valeur + 2*troisième valeur, ce qui donnerait ici 1*0+1*0.042+2*0.958 soit 1.958

Pour l’exemple ci-dessus je devrai obtenir :
2     1     0    1    2     1.997       2     2     2     1.958    2     2     2     2     1.999       2     2     1.99097   2     1.958       2     

Est-ce que quelqu’un aurait une solution ?
Merci d’avance smile
Julie

Dernière modification par Ayral (Le 22/09/2020, à 15:14)

Hors ligne

#2 Le 17/09/2020, à 16:41

kamaris

Re : [Résolu] Boucle remplacement de caractères et opérations

Avec awk ça devrait être assez rapide, peut-être y a-t-il plus court et rapide que ça :

awk '{gsub("1/1","2"); gsub("1/0|0/1","1"); gsub("0/0","0"); for (i=1;i<=NF;i++) if ($i ~ ":"){sub(".*:","",$i); split($i,a,","); $i=a[1]+a[2]+2*a[3]} print}' fichier

Rq : les espacements entre les champs ne sont pas préservés par cette commande.

Hors ligne

#3 Le 17/09/2020, à 17:22

pingouinux

Re : [Résolu] Boucle remplacement de caractères et opérations

Bonjour,
Autre solution, moins  concise, en python :

$ cat script.py 
#!/usr/bin/env python3
import sys, re
rec1=re.compile('(^|\s)([01]/[01])(:[.,\d]+)?($|\s)')
rec2=re.compile('(^|\s)2:(\S+)($|\s)')

def f1(obj):
   v1,v2=map(int,obj.group(2).split('/'))
   return obj.group(1)+str(v1+v2)+(obj.group(3) if obj.group(3) else "")+obj.group(4)

def f2(obj):
   v=tuple(map(float,obj.group(2).split(',')))
   return obj.group(1)+str(round(v[0]+v[1]+2*v[2],5))+obj.group(3)

with open(sys.argv[1]) as f: t=f.read()

t=rec1.sub(f1,t)
t=rec2.sub(f2,t)
print(t)

À appeler ainsi

./script.py fichier

Hors ligne

#4 Le 18/09/2020, à 07:43

Compte supprimé

Re : [Résolu] Boucle remplacement de caractères et opérations

Bonjour,

Juste pour le fun , autre approche avec python et sans expressions rationnelles:
(depuis une string , à modifier en conséquence pour un usage sur fichier)

s = "1/1     0/1     0/0    1/0    1/1     1/1:0,0.003,0.997       1/1     1/1     1/1     1/1:0,0.042,0.958     1/1     1/1     1/1     1/1     1/1:0,0.001,0.999       1/1     1/1     1/1:0,0.00903,0.99097   1/1     1/1:0,0.042,0.958       1/1  "
s= s.split()

def modifie(expression):
    if expression == '0/1' or expression == '1/0':
        return 1
    if expression == "1/1":
        return 2
    if expression == "0/0":
        return 0
    
for index,expression in enumerate(s):
    if ":" in expression:
        l_exp = expression.split(":")
        _somme = [float(i) for i in l_exp[1].split(",")]
        _somme = _somme[0] + _somme[1] + 2*_somme[2]
        s[index] = _somme
        
    else:
        s[index] = modifie(expression)
print(s)

#5 Le 18/09/2020, à 07:52

Compte supprimé

Re : [Résolu] Boucle remplacement de caractères et opérations

Si comme le laisse à penser l'exemple, toutes les expressions sont sous la forme "0/0" "1/0" "0/1" .... nous pourrions utiliser un dico à la place des tests

s = "1/1     0/1     0/0    1/0    1/1     1/1:0,0.003,0.997       1/1     1/1     1/1     1/1:0,0.042,0.958     1/1     1/1     1/1     1/1     1/1:0,0.001,0.999       1/1     1/1     1/1:0,0.00903,0.99097   1/1     1/1:0,0.042,0.958       1/1  "
s = s.split()
equivalence = {'0/1':1, '1/0':1, '1/1':2, '0/0':0}

def modifie(expression):
    return equivalence[expression]
    
for index,expression in enumerate(s):
    if ":" in expression:
        l_exp = expression.split(":")
        _somme = [float(i) for i in l_exp[1].split(",")]
        _somme = _somme[0] + _somme[1] + 2*_somme[2]
        s[index] = _somme
        
    else:
        s[index] = modifie(expression)
print(s)

#6 Le 22/09/2020, à 11:10

Julie M

Re : [Résolu] Boucle remplacement de caractères et opérations

Bonjour kamaris, pingouinux et pseudofab,

Je vous remercie pour vos réponses rapides à mon post. J'ai opté pour la solution de Kamaris et cela fonctionne parfaitement.
Effectivement les espacements entre les champs n'ont pas été préservés, il ne me reste plus qu'à trouver comment ajouter des tabulations comme délimitateur de champs.
Julie

Hors ligne

#7 Le 22/09/2020, à 15:13

Ayral

Re : [Résolu] Boucle remplacement de caractères et opérations

Modération : puisque tu as eu la réponse à ta question, il est d'usage de la passer en Résolu en modifiant ton premier message puis en rajoutant l'expression [Résolu] au début du sujet. Je le fais pour gagner du temps.


Pour mettre les retours de commande entre deux balises code, les explications sont là : https://forum.ubuntu-fr.org/viewtopic.php?id=1614731
Blog d'un retraité
Site de graphisme du fiston Loïc
Ubuntu 22.04 LTS sur un Thinkpad W540

Hors ligne

#8 Le 22/09/2020, à 16:51

kamaris

Re : [Résolu] Boucle remplacement de caractères et opérations

Julie M a écrit :

Effectivement les espacements entre les champs n'ont pas été préservés, il ne me reste plus qu'à trouver comment ajouter des tabulations comme délimitateur de champs.

Pour ça, il te suffit d'ajouter BEGIN{OFS="\t"} au début du programme awk, soit au final :

awk 'BEGIN{OFS="\t"} {gsub("1/1","2"); gsub("1/0|0/1","1"); gsub("0/0","0"); for (i=1;i<=NF;i++) if ($i ~ ":"){sub(".*:","",$i); split($i,a,","); $i=a[1]+a[2]+2*a[3]} print}' fichier

S'il avait fallu retrouver un espacement particulier entre chaque couple de champs, ça aurait été un peu plus compliqué.

Hors ligne