6
votes

Trouver et remplacer de nombreux mots

J'ai souvent besoin de faire de nombreux remplaçants dans les fichiers. Pour résoudre ce problème, j'ai créé deux fichiers old.text et nouveau.text . La première contient une liste de mots qui doivent être trouvés. La seconde contient la liste des mots qui devraient remplacer ceux-ci.

  • Tous mes fichiers utilisent UTF-8 et utilisent différentes langues.

    J'ai construit ce script, que j'espérais faire le remplacement. Tout d'abord, il lit old.text une ligne à la fois, puis remplace les mots de cette ligne dans INPUT.TXT avec les mots correspondants à partir du fichier nouveau.text . < / p> xxx

    Cependant, ma solution ne fonctionne pas bien. Lorsque j'exécute le script:

    • On Line 6, la commande SED ne sait pas où le numéro $ se termine.
    • Le numéro $ la variable est de changer sur "0 + 1", puis "0 + 1 + 1", quand il devrait passer à "1", puis "2".
    • La ligne avec awk ne semble pas faire quelque chose de plus que la copie de l'entrée.txt exactement comme pour produire.txt.

      Avez-vous des suggestions?

      Mise à jour:

      La réponse marquée fonctionne bien, cependant, j'utilise beaucoup ce script et il faut beaucoup d'heures pour terminer . Je propose donc une prime pour une solution pouvant compléter ces remplaçants beaucoup plus rapidement. Une solution à Bash, Perl ou Python 2 ira bien, à condition qu'il soit toujours compatible UTF-8. Si vous pensez qu'une autre solution utilisant d'autres logiciels couramment disponibles sur les systèmes Linux serait plus rapide, alors cela pourrait aller aussi bien, tant que d'énormes dépendances ne sont pas nécessaires.


6 commentaires

Avez-vous envisagé d'utiliser sed ?


J'ai mis à jour le script. SED -I "S / $ $ I / $ J / G" ./MAIN.FILE - Ajout de l'espace dans cette action. Faites-moi savoir si cela ne fonctionne pas et nous pouvons regarder plus loin.


Avez-vous essayé de fusionner les deux fichiers et de le faire comme fichier de script SED?


J'ai ajouté une autre réponse à cela. Je ne sais pas si c'était une bonne idée d'ajouter un autre au lieu de l'édition de l'existence. Mais espérons que cela aide.


Je pense que la solution la plus rapide peut être facilement écrite dans C. Vous envisagez-vous que des langues de script?


Qu'est-il arrivé à la balise Python?


12 Réponses :


8
votes
  • une ligne 6, la commande sed ne sait pas où se termine le numéro $. strong> li>

    Essayez de cibler la variable avec des guillemets doubles p>

    LinefromNewwords = $ (sed -n "Numéro" $ "P NewWords.txt) P> blockQuote>

    • La variable $ NUMBER change sur "0 + 1", puis "0 + 1 + 1", quand il devrait passer à "1", puis "2". strong> li> li> ul>

      fais cela à la place: P>

      Number = `EXPR $ Number + 1` P> blockQuote>

      • La ligne avec AWK n'apparaît pas faire quelque chose de plus que la copie de l'entrée.txt exactement comme pour produire.txt. strong> li> ul>

        awk ne prendra pas de variables en dehors de sa portée. Les variables définies par l'utilisateur dans AWK doivent être définies lorsqu'elles sont utilisées ou prédéfinies dans la déclaration de bourse de l'AWK. Vous pouvez inclure des variables shell en utilisant l'option -v code>. p>

        Voici une solution dans bash code> qui ferait ce dont vous avez besoin. p>

        Solution Bash: strong> P>

        #!/bin/bash
        
        while read -r sub && read -r rep <&3; do
          sed -i "s/ "$sub" / "$rep" /g" main.file
        done <old.text 3<new.text
        


0 commentaires

4
votes

Pourquoi pas à

paste -d/ oldwords.txt newwords.txt |\
sed -e 's@/@ / @' -e 's@^@s/ @' -e 's@$@ /g@' >/tmp/$$.sed

sed -f /tmp/$$.sed original >changed

rm /tmp/$$.sed


0 commentaires

1
votes

à la ligne 6, la commande sed ne sait pas où se termine le numéro $. P> XXX PRE>

Je ne suis pas sûr de la citation, mais {Number} p fonctionnera - peut-être "$ {numéro} p" p>

La variable $ NUMBER change sur "0 + 1", puis "0 + 1 + 1", quand il devrait passer à "1", puis "2". P> blockQquote>

L'évaluation entière arithmétique dans Bash peut être effectuée avec $ (()) et est meilleure que eval code> (eval = Evil). P>

s/\bni3\b/nǐ/g


0 commentaires

2
votes

Ce script Python 2 forme les anciens mots en une seule expression régulière, substitue ensuite le nouveau mot correspondant basé sur l'index de l'ancien mot qui correspondait. Les anciens mots ne sont assortis que s'ils sont distincts. Cette distinction est appliquée en entourant le mot dans R '\ B' qui est la limite de mot d'expression régulière.

Entrée provient de la commande Commandline (leur alternative a été commente que j'ai utilisée pour le développement au ralenti). La sortie est sur stdout p>

Le texte principal est numérisé une seule fois dans cette solution. Avec l'entrée de JayPals Réponse, la sortie est la même. P>

Total characters in text: 116413
Total words in text: 17114
Total distinct words in text: 209
Top 10 distinct word occurences in text: 2664 = 15.57%
  • Paddy. Li> ul> p>


0 commentaires

1
votes

Ceci devrait réduire strong> le temps par certains moyens que cela évite les em> inutiles em> boucles.

Fusionner deux fichiers d'entrée: h3>

suppose que vous avez Deux fichiers d'entrée, Old.Text forts> contenant tous les Substitutions em> et nouveau.text strong> contenant tous les remplaçants p>. P>.

Nous allons créer un nouveau fichier texte qui agira en tant que script code> SED CODE> à votre fichier principal à l'aide des AWK CODE> ONE-LINER: P>

sed -f merge.text input_file

[jaypal:~/Temp] cat input_file 
 12 adsflljl
 12 hgfahld
 12 ash;al
 13 a;jfda
 13 asldfj
 15 ;aljdf
 16 a;dlfj
 19 adads
 19 adfasf
 20 aaaadsf

[jaypal:~/Temp] sed -f merge.text input_file 
 12 adsflljl
 12 hgfahld
 12 ash;al
 13 a;jfda
 13 asldfj
 15 ;aljdf
 16 a;dlfj
 A adads
 A adfasf
 B aaaadsf


0 commentaires

1
votes

Cela pourrait fonctionner pour vous:

paste {old,new}words.txt | 
sed 's,\(\w*\)\s*\(\w*\),s!\\<\1\\>!\2!g,' | 
sed -i -f - text.txt


0 commentaires

1
votes

Voici un script Python 2 qui devrait être à la fois spatial et temps efficace: xxx

ici est en action: xxx

Modifier: Batte de chapeau à @ Paddy3118 pour la manipulation des espaces.


0 commentaires

2
votes

J'aime ce genre de questions, voici ma réponse:

Premier pour la Shake of Simplicity, pourquoi ne pas utiliser qu'un fichier avec source et traduction. Je veux dire: (nom de fichier chantethis) p> xxx pré>

alors vous pouvez définir un séparateur approprié dans le script. (fichier remplacement de fichier.sh) p> xxx pré>

prenez cet exemple (fichier changeme) p> xxx pré>

appelez-le avec p> xxx pré>

et vous obtiendrez p> xxx pré>

prendre note de l'amusement "i" avec SED. "-J'ai" signifie remplacer dans le fichier source et "i" dans la commande S // signifie Ignorer CAS-CAS-EXTENDEMENT - Vérifiez votre implémentation SED - P>

Notez bien que la boucle est horreur qu'un python ou un langage de script similaire. En fonction de vos besoins, vous pouvez faire une imbriquée pendant laquelle, un sur le fichier source et une intérieure en boucle les traductions (modifications). Écho à tous à STDOUT pour la flexibilité des tuyaux. P>

#!/bin/bash

SEP=${1}
TRANSLATION=${2}
FILE=${3}
while read line
do
   while read transline
   do
      origin=${transline%%${SEP}*}
      dest=${transline##*${SEP}}
      line=$(echo $line | sed "s/${origin}/${dest}/gI")
   done < $TRANSLATION
   echo $line
done < $FILE


0 commentaires

1
votes

Voici une solution à Perl. Il peut être simplifié si vous avez combiné vos listes de mots d'entrée dans une liste: chaque ligne contenant la carte des mots anciens et nouveaux. XXX PRE>

Fichier de mots ancien: P>

$ perl replace.pl old.txt new.txt input.txt
12 adsflljl
12 hgfahld
12 ash;al
13 a;jfda
13 asldfj
15 ;aljdf
16 a;dlfj
A adads
A adfasf
B aaaadsf


0 commentaires

1
votes

Je ne sais pas pourquoi la plupart des affiches précédentes insistent sur l'utilisation d'expressions régulières pour résoudre cette tâche, je pense que cela sera plus rapide que la plupart (sinon la méthode la plus rapide).

use warnings;
use strict;

open (my $fh_o, '<', "old.txt");
open (my $fh_n, '<', "new.txt");

my @hay = <>;
my @old = map {s/^\s*(.*?)\s*$/$1/; $_} <$fh_o>;
my @new = map {s/^\s*(.*?)\s*$/$1/; $_} <$fh_n>;

my %r;
;  @r{@old} = @new;

print defined  $r{$_} ? $r{$_} : $_ for split (
  /(\s+)/, "@hay"
);


0 commentaires

1
votes

Edit - Je viens de remarquer que deux réponses comme les miennes sont déjà là ... Donc, vous pouvez simplement ignorer le mien :)

Je crois que ce script Perl, bien que ne pas utiliser Fancy SAD ou Awk Thkies, le travail équitablement ... P>

J'ai pris la liberté d'utiliser un autre format d'ancien_word à new_word: le format CSV. Si c'est trop compliqué pour le faire, faites-le-moi savoir et je vais ajouter un script qui prend votre vieille.txt, New.txt et construit le fichier CSV. P>

Prenez-le sur une course et faites-le-moi savoir ! P>

Au fait - si l'un de vous Perl Gurus ici peut suggérer une manière plus répandue de faire quelque chose que je fais ici, j'aimerai lire le commentaire: P>

    #! /usr/bin/perl
    # getting the user's input
    if ($#ARGV == 1)
        {
        $LUT_file = shift;
        $file = shift;
        $outfile = $file . ".out.txt";
        }
    elsif ($#ARGV == 2)
        {
        $LUT_file = shift;
        $file = shift;
        $outfile = shift;
        }
    else { &usage; }

    # opening the relevant files

    open LUT, "<",$LUT_file or die "can't open $signal_LUT_file for reading!\n : $!";
    open FILE,"<",$file or die "can't open $file for reading!\n : $!";
    open OUT,">",$outfile or die "can't open $outfile for writing\n :$!";

    # getting the lines from the text to be changed and changing them
    %word_LUT = ();
    WORD_EXT:while (<LUT>)
        {
        $_ =~ m/(\w+),(\w+)/;
        $word_LUT{ $1 } =  $2 ;
        }
    close LUT;

    OUTER:while ($line = <FILE>)
        {
        @words = split(/\s+/,$line);
        for( $i = 0; $i <= $#words; $i++)
            {
            if ( exists ($word_LUT { $words[$i] }) ) 
                {
                $words[$i] = $word_LUT { $words[$i] };
                }

            }
        $newline = join(' ',@words);
        print "old line - $line\nnewline - $newline\n\n";
        print OUT $newline . "\n";

        }   
    # now we have all the signals needed in the swav array, build the file.

        close OUT;close FILE;

    # Sub Routines
    #
    #

    sub usage(){
    print "\n\n\replacer.pl Usage:\n";
    print "replacer.pl <LUT file> <Input file> [<out file>]\n\n";
    print "<LUT file> -    a LookUp Table of words, from the old word to the new one.
    \t\t\twith the following csv format:
    \t\t\told word,new word\n";
    print "<Input file>       -    the input file\n";
    print "<out file>         -    out file is optional. \nif not entered the default output file will be: <Input file>.out.txt\n\n";

    exit;
    }


0 commentaires

2
votes

Une solution de Perl générale que j'ai constatée de bien fonctionner pour remplacer les clés sur une carte avec leurs valeurs associées est la suivante:

my %map = (
    19 => 'A',
    20 => 'B',
);

my $key_regex = '(' . join('|', keys %map) . ')';

while (<>) {
    s/$key_regex/$map{$1}/g;
    print $_;
}


0 commentaires