2016-05-23 8 views
-2

i mit einer Substitution etwas Hilfe möchte ich auf die Zeilen einer Datei tun möchten, die wie folgt aussehen:Perl - Substitute nach n-ten Begrenzer

aoipp;dadada.12312;ss;1245454;Xiop;12.12;45.3;47.897;31.5; 
asdfafd;14355.54664;peasd;125.1;900.2;76.897;67.456;asdfdf; 
perio;777.2;ipoes;900.34;2;1980.45;870.98;67.67; 

ich jeden . mit , ersetzen wollen, sondern erst nach das fünfte Vorkommen des Trennzeichens ;. Alles andere muss unverändert bleiben. So ist die gewünschte Ausgabedatei würde wie folgt aussehen:

aoipp;dadada.12312;ss;1245454;Xiop;12,12;45,3;47,897;31,5; 
asdfafd;14355.54664;peasd;125.1;900.2;76,897;67,456;asdfdf; 
perio;777.2;ipoes;900.34;2;1980,45;870,98;67,67; 

Ich bin daran interessiert, dies vor allem in Perl zu tun, damit ich es in ein größeres Programm integrieren können, aber alle Lösungen in bash/awk sind willkommen. Danke im Voraus.

+0

Ich weiß nicht, warum Leute mich weiter downvoting. Alle Antworten unten erreichten das gewünschte Ergebnis, aber ich kann nur eins annehmen. – onlyf

+2

Wahrscheinlich, weil Sie nicht versucht haben, das Problem selbst zu lösen. – Sobrique

+4

Fair genug. Ich weiß nicht so viel Regex wie erforderlich, um damit umzugehen. Das nächste Mal werde ich einige meiner gescheiterten Versuche veröffentlichen, wenn ich eine Frage beginne. – onlyf

Antwort

3

Diese awk Einzeiler für Sie arbeiten sollten:

awk -F';' -v OFS=";" '{for(i=6;i<=NF;i++)gsub("[.]",",",$i)}7' file 

Aus dem sechsten Feld beginnt (; getrennt), für jedes Feld alle durch ,. ersetzen.

-Test mit Ihren Daten:

kent$ cat f 
aoipp;dadada.12312;ss;1245454;Xiop;12.12;45.3;47.897;31.5; 
asdfafd;14355.54664;peasd;125.1;900.2;76.897;67.456;asdfdf; 
perio;777.2;ipoes;900.34;2;1980.45;870.98;67.67; 

kent$ awk -F';' -v OFS=";" '{for(i=6;i<=NF;i++)gsub("[.]",",",$i)}7' f 
aoipp;dadada.12312;ss;1245454;Xiop;12,12;45,3;47,897;31,5; 
asdfafd;14355.54664;peasd;125.1;900.2;76,897;67,456;asdfdf; 
perio;777.2;ipoes;900.34;2;1980,45;870,98;67,67; 
+0

Vielen Dank. Diese "7" ist am Ende etwas verwirrend, aber was Sie vorgeschlagen haben, funktioniert. – onlyf

+0

@onlyf es tut nur Drucken, – Kent

+1

Der erste Arg für Awks * sub() - Funktionen ist ein Regexp, kein String, also verwenden Sie reguläre Trennzeichen '/.../' nicht String Delimiter '" ... "' als Letzteres macht Ihren Code komplizierter, da awk die Zeichenfolge in eine Regexp konvertieren muss, bevor Sie sie verwenden. –

0
# this should do your work 
    sed -i 's/;/,/6g' filename 

    cat filename 
    aoipp;dadada.12312;ss;1245454;Xiop;12.12,45.3,47.897,31.5, 
    asdfafd;14355.54664;peasd;125.1;900.2;76.897,67.456,asdfdf, 
    perio;777.2;ipoes;900.34;2;1980.45,870.98,67.67, 
+0

Ich brauche '; s (Semikolon) nicht zu ersetzen, ich muss' ersetzen '. (Punkt) mit ',' (Komma) nach dem fünften Vorkommen von ';' – onlyf

3

benutzen ich ein Array-Slice @fields[ 5 .. $#fields ] nur die Elemente für den Zugriff geändert werden.

#!/usr/bin/perl 
use warnings; 
use strict; 

my @input = qw(aoipp;dadada.12312;ss;1245454;Xiop;12.12;45.3;47.897;31.5; 
       asdfafd;14355.54664;peasd;125.1;900.2;76.897;67.456;asdfdf; 
       perio;777.2;ipoes;900.34;2;1980.45;870.98;67.67; 
      ); 

my @expected = qw(aoipp;dadada.12312;ss;1245454;Xiop;12,12;45,3;47,897;31,5; 
        asdfafd;14355.54664;peasd;125.1;900.2;76,897;67,456;asdfdf; 
        perio;777.2;ipoes;900.34;2;1980,45;870,98;67,67; 
       ); 

sub process { 
    my (@input) = @_; 
    my @output; 
    for my $line (@input) { 
     my @fields = split /;/, $line; 
     s/\./,/ for @fields[ 5 .. $#fields ]; 
     push @output, join ';', @fields, q(); 
    } 
    return \@output 
} 

use Test::More tests => 1; 
is_deeply(process(@input), \@expected); 
3
while (my $line = <DATA>) { 
    if ($line =~ /^(?:[^;]*;){5}/) { 
     substr($line, $+[0]) =~ y/./,/; 
    } 
    print $line; 
} 
__DATA__ 
aoipp;dadada.12312;ss;1245454;Xiop;12.12;45.3;47.897;31.5; 
asdfafd;14355.54664;peasd;125.1;900.2;76.897;67.456;asdfdf; 
perio;777.2;ipoes;900.34;2;1980.45;870.98;67.67; 
1
perl -pe 's/(.*?;){6}\K(.*)/$2 =~ s!\.!,!rg /ge' 
  1. alles überspringen bis zum 6. ; ((.*?;){6}\K),
  2. und die Substitution aply. , zum Rest der Linie ($2 =~ s!\.!,!rg)