2010-11-24 20 views
3

J'ai un fichier .h, entre autres, contenant des données dans ce formatScript pour migrer des données d'une source à une autre

struct X[]{ 
{"Field", "value1 value2 value"}, 
{"Field2", "value11 value12 value232"}, 
{"Field3", "x y z"}, 
{"Field4", "a bbb s"}, 
{"Field5", "sfsd sdfdsf sdfs"}; 
/****************/ 
}; 

J'ai un fichier texte contenant des valeurs que je veux remplacer dans .h fichier avec de nouvelles valeurs

value1 Valuesdfdsf1 
value2 Value1dfsdf 
value3 Value1_another 
sfsd  sfsd_ewew 
sdfdsf sdfdsf_ew 
sdfs  sfsd_new 

Et le fichier .h résultant contiendra les remplacements du fichier texte ci-dessus. Tout le reste reste le même.

struct X[]{ 
    {"Field1", "value11 value12 value232"}, 
    {"Field2", "value11 value12 value232"}, 
    {"Field3", "x y z"}, 
    {"Field4", "a bbb s"}, 
    {"Field5", "sfsd_ewew sdfdsf_ew sdfs_new"}; 
    /****************/ 
    }; 

S'il vous plaît aidez-moi à venir avec une solution pour l'accomplir en utilisant des outils unix: awk, perl, bash, sed, etc

+0

Les paires de valeurs de champ sont-elles toujours sur la même ligne et les valeurs sont-elles séparées par un seul espace? – DVK

+0

espace/tabulation, au moins un espace est certain – vehomzzz

+0

La valeur 2 de la première ligne ne doit-elle pas être remplacée par Value1dfsdf ? – DVK

Répondre

0

Ce script devrait fonctionner
keyval est le fichier contenant des paires de valeurs clés
filetoreplace est le fichier contenant des données à modifier
Le fichier nommé changé contiendra les changements

#!/bin/sh 
echo 

keylist=`cat keyval | awk '{ print $1}'` 


while read line 
do 

for i in $keylist 
do 


if echo $line | grep -wq $i; then 

    value=`grep -w $i keyval | awk '{print $2}'` 
    line=`echo $line | sed -e "s/$i/$value/g"` 
fi 

done 

echo $line >> changed 

done < filetoreplace 
3
cat junk/n2.txt | perl -e '{use File::Slurp; my @r = File::Slurp::read_file("junk/n.txt"); my %r = map {chomp; (split(/\s+/,$_))[0,1]} @r; while (<>) { unless (/^\s*{"/) {print $_; next;}; my ($pre,$values,$post) = ($_ =~ /^(\s*{"[^"]+", ")([^"]+)(".*)$/); my @new_values = map { exists $r{$_} ? $r{$_}:$_ } split(/\s+/,$values); print $pre . join(" ",@new_values) . $post . "\n"; }}'  

Résultat:

struct X[]{ 
{"Field", "value1 Value1dfsdf value"}, 
{"Field2", "value11 value12 value232"}, 
{"Field3", "x y z"}, 
{"Field4", "a bbb s"}, 
{"Field5", "sfsd_ewew sdfdsf_ew sfsd_new"}; 
/****************/ 
}; 

code démêlé:

use File::Slurp; 
my @replacements = File::Slurp::read_file("junk/n.txt"); 
my %r = map {chomp; (split(/\s+/,$_))[0,1]} @replacements; 
while (<>) { 
    unless (/^\s*{"/) {print $_; next;} 
    my ($pre,$values,$post) = ($_ =~ /^(\s*{"[^"]+", ")([^"]+)(".*)$/); 
    my @new_values = map { exists $r{$_} ? $r{$_} : $_ } split(/\s+/, $values); 
    print $pre . join(" ",@new_values) . $post . "\n"; 
} 
+0

Dieu je déteste comment Perl ressemble. Pouvoir par la laideur! Suivant sur ma liste d'apprentissage si :) – Morlock

+1

@Morlock - Ce n'est pas comment ** Perl ** ressemble. Voilà à quoi ressemble un Perl ** one-liner **, conçu pour prendre le moins de place possible sur la corde. Écrit dans un style de codage Perl approprié, une grande majorité des signes de ponctuation dans le code ci-dessus disparaissent et laissent un programme réellement lisible. Les seules pièces qui semblent encore encodées sont des expressions régulières qui semblent identiques à 100% dans toutes les langues. – DVK

+0

Si quelqu'un pouvait décomposer ligne par ligne ce que tout cela signifie .... – vehomzzz

2
#!/usr/bin/perl 

use strict; use warnings; 

# you need to populate %lookup from the text file 
my %lookup = qw(
    value1 Valuesdfdsf1 
    value2 Value1dfsdf 
    value3 Value1_another 
    sfsd  sfsd_ewew 
    sdfdsf sdfdsf_ew 
    sdfs  sfsd_new 
); 

while (my $line = <DATA>) { 
    if ($line =~ /^struct \w+\Q[]/) { 
     print $line; 
     process_struct(\*DATA, \%lookup); 
    } 
    else { 
     print $line; 
    } 
} 

sub process_struct { 
    my ($fh, $lookup) = @_; 

    while (my $line = <$fh>) { 
     unless ($line =~ /^{"(\w+)", "([^"]+)"}([,;])\s+/) { 
      print $line; 
      return; 
     } 
     my ($f, $v, $p) = ($1, $2, $3); 
     $v =~ s/(\w+)/exists $lookup->{$1} ? $lookup->{$1} : $1/eg; 
     printf qq|{"%s", "%s"}%s\n|, $f, $v, $p; 
    } 
    return; 
} 

__DATA__ 
struct X[]{ 
{"Field", "value1 value2 value"}, 
{"Field2", "value11 value12 value232"}, 
{"Field3", "x y z"}, 
{"Field4", "a bbb s"}, 
{"Field5", "sfsd sdfdsf sdfs"}; 
/****************/ 
}; 
1

Voici un programme simple recherche:

use strict; 
use warnings; 
use File::Copy; 

use constant { 
    OLD_HEADER_FILE => "headerfile.h", 
    NEW_HEADER_FILE => "newheaderfile.h", 
    DATA_TEXT_FILE => "data.txt", 
}; 

open (HEADER, "<", OLD_HEADER_FILE) or 
die qq(Can't open file old header file ") . OLD_HEADER_FILE . qq(" for reading); 

open (NEWHEADER, ">", NEW_HEADER_FILE) or 
die qq(Can't open file new header file ") . NEW_HEADER_FILE . qq(" for writing); 

open (DATA, "<", DATA_TEXT_FILE) or 
die qq(Can't open file data file ") . DATA_TEXT_FILE . qq(" for reading); 

# 
# Put Replacement Data in a Hash 
# 

my %dataHash; 
while (my $line = <DATA>) { 
    chomp($line); 
    my ($key, $value) = split (/\s+/, $line); 
    $dataHash{$key} = $value if ($key and $value); 
} 
close (DATA); 

# 
# NOW PARSE THOUGH HEADER 
# 

while (my $line = <HEADER>) { 
    chomp($line); 
    if ($line =~ /^\s*\{"Field/) { 
     foreach my $key (keys(%dataHash)) { 
      $line =~ s/\b$key\b/$dataHash{$key}/g; 
     } 
    } 
    print NEWHEADER "$line\n"; 
} 

close (HEADER); 
close (NEWHEADER); 
copy(NEW_HEADER_FILE, OLD_HEADER_FILE) or 
    die qq(Unable to replace ") . OLD_HEADER_FILE . qq(" with ") . NEW_HEADER_FILE . qq("); 

je pouvais le rendre plus efficace en utilisant map, mais qui le rend plus difficile à comprendre.

En gros:

  • J'ouvre trois fichiers, l'en-tête d'origine, le nouvel en-tête je construis, et le fichier de données
  • j'ai mis mes données dans un hachage où le texte de remplacement est calée par le texte original. (J'aurais pu le faire dans l'autre sens si je le voulais
  • Je passe ensuite par chaque ligne de l'en-tête d'origine ** Si je vois une ligne qui ressemble à une ligne de champ, je sais que je devrais faire un remplacement. ** pour chaque entrée dans mon %dataHash, je fais une substitution du $key avec la valeur de remplacement $dataHash{$key}. J'utilise le \b pour marquer mot boundries. de cette façon, field11 n'est pas substitué parce que je vois field1 dans ** Maintenant, j'écris la ligne dans mon nouveau fichier d'en-tête.Si je n'ai rien remplacé, je réécris simplement la ligne d'origine
  • terminer, je copie le nouvel en-tête sur l'ancien fichier d'en-tête.
+0

Merci pour la version alternative plus facile-sur-le-oeil :) – Morlock

0

Ceci peut être un peu lent si vos fichiers sont gros.

gawk -F '[ \t]*|"' 'FNR == NR {repl[$1]=$2;next}{for (f=1;f<=NF;++f) for (r in repl) if ($f == r) $f=repl[r]; print} ' keyfile file.h