2013-02-04 6 views
1

Désolé pour cette question apparemment simple, mais passé trop de temps à essayer de trouver la solution partout et d'essayer différentes options sed. J'ai juste besoin de remplacer tous les points par des virgules dans un fichier texte, mais seulement entre deux positions. À titre d'exemple, de:sed: remplacez un caractère seulement entre deux positions

1.3.5.7.9 

à

1.3,5,7.9 

, remplacez. par, entre les positions 3 à 7. Merci! EDITED: désolé, j'ai fait semblant de simplifier le problème, mais comme aucune des 3 premières réponses ne fonctionne à cause d'un manque de détails dans ma question, laissez-moi aller un peu plus loin. Le point important est de remplacer tous les points par des virgules dans un intervalle de positions sans connaître le reste de la chaîne:

Here some text. I don't want to change. 10.000 usd 234.566 usd Continuation text. 
More text. No need to change this part. 345 usd 76.433 usd Text going on. So on. 

Ceci est un fichier texte de largeur fixe, dans les colonnes, et je dois changer le format international des numéros , en remplaçant les points par des virgules. Je connais juste les positions initiales et finales où j'ai besoin de chercher et éventuellement remplacer les points. Évidemment, toutes les figures n'ont pas de points (seulement ceux de plus de 1000). Merci.

Répondre

2

Réécrire la réponse après la clarification de la question:

Ceci est difficile à manipuler avec sed seulement, mais peut être simplifiée avec d'autres utilitaires standards comme cut et paste:

$ start=40 
$ end=64 
$ paste -d' ' <(cut -c -$((start-1)) example.txt) \ 
> <(cut -c $((start+1))-$((end-1)) example.txt | sed 'y/./,/') \ 
> <(cut -c $((end+1))- example.txt) 
Here some text. I don't want to change. 10,000 usd 234,566 usd Continuation text. 
More text. No need to change this part. 345 usd 76,433 usd Text going on. So on. 

(> signifie juste la continuation de la ligne précédente < sont réels). Ceci est bien sûr très inefficace, mais conceptuellement simple.

J'ai utilisé toutes les choses +1 et -1 pour se débarrasser des espaces supplémentaires. Je ne sais pas si vous en avez besoin.

Une solution pure sed (accrochez-vous):

$ sed "s/\(.\{${start}\}\)\(.\{$((end-start))\}\)/\1\n\2\n/;h;s/.*\n\(.*\)\n.*/\1/;y/./,/;G;s/^\(.*\)\n\(.*\)\n\(.*\)\n\(.*\)$/\2\1\4/" example.txt 
Here some text. I don't want to change. 10,000 usd 234,566 usd Continuation text. 
More text. No need to change this part. 345 usd 76,433 usd Text going on. So on. 

GNU sed:

$ sed -r "s/(.{${start}})(.{$((end-start))})/\1\n\2\n/;h;s/.*\n(.*)\n.*/\1/;y/./,/;G;s/^(.*)\n(.*)\n(.*)\n(.*)$/\2\1\4/" example.txt 
Here some text. I don't want to change. 10,000 usd 234,566 usd Continuation text. 
More text. No need to change this part. 345 usd 76,433 usd Text going on. So on. 
+0

Sory, j'espère que la question est un peu plus claire maintenant. –

+0

@jm_ J'ai changé la réponse en fonction de la question clarifiée. –

+0

Décidément, sed n'est pas toujours la solution la plus simple! Merci pour votre écriture. Je vais ajouter ci-dessous ce que j'ai trouvé plus pratique ... –

1


J'essaie de simplifier l'expression rationnelle, mais plus permissive.

echo 1.3.5.7.9 | sed -r "s/^(...).(.).(..)/\1,\2,\3/" 
1.3,5,7.9 

PS: Cela ne fonctionne pas avec BSD sed.

1
$ echo "1.3.5.7.9" | 
gawk -v s=3 -v e=7 '{ 
    print substr($0,1,s-1) gensub(/\./,",","g",substr($0,s,e-s+1)) substr($0,e+1) 
}' 
1.3,5,7.9 
1

Ceci est plutôt difficile à faire en sed pur. Si vous n'êtes pas strictement contraint à sed, je suggère d'utiliser un autre outil pour le faire. La solution basée sur gawk d'Ed Morton est probablement le moyen le moins maladroit (sans jeu de mots) de résoudre ce problème.

Voici un exemple d'utilisation sed pour faire le travail de grognement, mais enveloppées dans une fonction bash pour la simplicité:

function transform() { 
    line=$1 
    start=$2 
    end=$3 
    # Save beginning and end of line 
    front=$(echo $line | sed -e "s/\(^.\{$start\}\).*$/\1/") 
    back=$(echo $line | sed -e "s/^.\{$end\}//") 
    # Translate characters 
    line=$(echo $line | sed -e 'y/\./,/') 
    # Restore unmodified beginning/end 
    echo $line | sed -e "s/^.\{$start\}/$front/" -e "s/\(^.\{$end\}\).*$/\1$back/" 
} 

appeler cette fonction comme:

$ transform "1.3.5.7.9" 3 7 
1.3,5,7.9 
0

Merci à tous. Ce que je trouve autour (pas mon mérite) que des solutions simples sont:

  1. Pour les fichiers à largeur fixe:

    awk -F "" 'OFS="";{for (j=2;j<= 5;j++) if ($j==".") $j=","}'1 
    

va changer tous les points en virgules de la 2ème position à la 5e .

  1. Pour les fichiers délimités par des tabulations champs:

    awk -F'\t' 'OFS="\t" {for (j=2;j<=5;j++) gsub(/\./,",",$j)}'1 
    

va changer tous les points en comas à partir du 2ème champ au 5ème. Espoir qui peut aider quelqu'un: ne pouvait pas imaginer que ce serait si difficile au début.

Questions connexes