2014-07-02 7 views
1

Je travaille actuellement sur un code qui change certains mots en mots shakespeariens. Je dois extraire les phrases qui contiennent les mots et les imprimer dans un autre fichier. J'ai dû supprimer .START au début de chaque fichier.Comment trouver la position d'un mot en utilisant un compteur?

D'abord je diviser les fichiers avec le texte par des espaces, alors maintenant j'ai les mots. Ensuite, j'ai itéré les mots à travers un hachage. Les clés et les valeurs de hachage proviennent d'un fichier délimité par des tabulations structuré comme suit, OldEng/ModernEng (lc_Shakespeare_lexicon.txt). En ce moment, j'essaie de comprendre comment trouver la position exacte de chaque mot anglais moderne trouvé, changez-le en shakespearien; Ensuite, trouvez les phrases avec les mots de changement et imprimez-les dans un fichier différent. La majeure partie du code est terminée sauf pour cette dernière partie. Voici mon code à ce jour:

#!/usr/bin/perl -w 
use diagnostics; 
use strict; 

#Declare variables 
my $counter=(); 
my %hash=(); 
my $conv1=(); 
my $conv2=(); 
my $ssph=(); 
my @text=(); 
my $key=(); 
my $value=(); 
my $conversion=(); 
my @rmv=(); 
my $splits=(); 
my $words=(); 
my @word=(); 
my $vals=(); 
my $existingdir='/home/nelly/Desktop'; 
my @file='Sentences.txt'; 
my $eng_words=(); 
my $results=(); 
my $storage=(); 

#Open file to tab delimited words 

open (FILE,"<", "lc_shakespeare_lexicon.txt") or die "could not open  lc_shakespeare_lexicon.txt\n"; 

#split words by tabs 

while (<FILE>){ 
    chomp($_); 
    ($value, $key)= (split(/\t/), $_); 
    $hash{$value}=$key; 
} 

#open directory to Shakespearean files 

my $dir="/home/nelly/Desktop/input"; 
opendir(DIR,$dir) or die "can't opendir Shakespeare_input.tar.gz"; 
#Use grep to get WSJ file and store into an array 

my @array= grep {/WSJ/} readdir(DIR); 

#store file in a scalar 
foreach my $file(@array){ 

    #open files inside of input 

    open (DATA,"<", "/home/nelly/Desktop/input/$file") or die "could not open $file\n"; 
    #loop through each file 

    while (<DATA>){ 
     @text=$_; 
     chomp(@text); 
    #Remove .START 
    @rmv=grep(!/.START/, @text); 

foreach $splits(@rmv){ 
    #split data into separate words 
    @word=(split(/ /, $splits)); 
    #Loop through each word and replace with Shakespearean word that exists 
    $counter=0; 

foreach $words(@word){ 
     if (exists $hash{$words}){ 
      $eng_words= $hash{$words}; 
      $results=$counter; 
      print "$counter\n"; 
      $counter++; 

#create a new directory and store senteces with Shakespearean words in new file called "Sentences.txt" 
mkdir $existingdir unless -d $existingdir; 
open my $FILE, ">>", "$existingdir/@file", or die "Can't open  $existingdir/conversion.txt'\n"; 
#print $FILE "@words\n"; 

close ($FILE); 

       }   
      } 
     } 
    } 
} 

close (FILE); 
close (DIR); 
+1

Pourriez-vous poster des données d'entrée? – fugu

+2

Vous perdez certains des avantages de 'my' en déclarant les variables avant qu'elles ne soient nécessaires. En outre, toutes ces affectations (sauf 'my $ existingdir = '/ home/nelly/Desktop'; my @ file = 'Sentences.txt';') sont inutiles. – ikegami

+0

Très probablement, vous allez utiliser 'index'' pos' et autres - comme dans cette [SO similaire question (jetez un oeil sur les réponses)] (http://stackoverflow.com/a/4856558/2019415) . Je ne sais pas si vous configurez votre recherche '% hash' correctement ici cependant. Essayez d'utiliser ['Data :: Dumper'] (https://metacpan.org/pod/Data::Dumper) ou [' Data :: Printer'] (https://metacpan.org/release/Data-Printer) pour voir comment il est rempli. –

Répondre

3

traitement du langage naturel est très difficile d'obtenir le droit, sauf dans les cas insignifiants, par exemple, il est difficile de définir exactement ce que l'on entend par un mot ou une phrase, et il est difficile à distinguer entre guillemets simples et une apostrophe quand ils sont à la fois représentés en utilisant la U+0027 « apostrophe » caractère '

Sans données exemple, il est difficile d'écrire une solution fiable, mais le programme devrait être raisonnablement ci-dessous fermer

S'il vous plaît noter les éléments suivants

  • use warnings est préférable de -w sur la ligne de tralala

  • Un programme devrait contenir quelques commentaires que possible aussi longtemps qu'il est compréhensible. Trop de commentaires rendent le programme plus gros et plus difficile à saisir sans ajouter de nouvelles informations. Le choix des identificateurs devrait rendre le code essentiellement auto-documenté

  • Je crois que use diagnostics est inutile. La plupart des messages sont assez explicites et diagnostics peuvent produire de grandes quantités de production inutiles

  • Parce que vous ouvrez plusieurs fichiers, il est plus concis use autodie qui éviteront la nécessité de tester explicitement chaque open appel à succès

  • Il est préférable d'utiliser des handles de fichiers lexicaux, tels que open my $fh ... au lieu de globaux, comme open FH .... D'une part un descripteur de fichier lexical sera fermé implicitement quand il est hors de portée, ce qui contribue à ranger le programme beaucoup en faisant close explicites appels inutiles

  • J'ai supprimé toutes les déclarations variables du haut de le programme sauf ceux qui ne sont pas vides. Le programme minimise le mot original en utilisant lc avant de vérifier s'il existe une entrée correspondante dans le hachage.Si une traduction est trouvée, le nouveau mot majuscule à l'aide ucfirst si le mot d'origine a commencé par une lettre majuscule

  • J'ai écrit une expression régulière qui prendra la phrase suivante à partir du début de la chaîne $content. Mais c'est l'une des choses que je ne peux pas obtenir le droit sans données de l'échantillon, et il pourrait bien y avoir des problèmes, par exemple, avec des phrases qui se terminent par un guillemet de fermeture ou une parenthèse fermante

use strict; 
use warnings; 
use autodie; 

my $lexicon  = 'lc_shakespeare_lexicon.txt'; 
my $dir   = '/home/nelly/Desktop/input'; 
my $existing_dir = '/home/nelly/Desktop'; 
my $sentences = 'Sentences.txt'; 

my %lexicon = do { 
    open my ($fh), '<', $lexicon; 
    local $/; 
    reverse(<$fh> =~ /[^\t\n\r]+/g); 
}; 

my @files = do { 
    opendir my ($dh), $dir; 
    grep /WSJ/, readdir $dh; 
}; 

for my $file (@files) { 

    my $contents = do { 
    open my $fh, '<', "$dir/$file"; 
    join '', grep { not /\A\.START/ } <$fh>; 
    }; 

    # Change any CR or LF to a space, and reduce multiple spaces to single spaces 
    $contents =~ tr/\r\n/ /; 
    $contents =~ s/ {2,}/ /g; 

    # Find and process each sentence 
    while ($contents =~/\s* (.+?[.?!]) (?= \s+ [A-Z] | \s* \z) /gx) { 
    my $sentence = $1; 
    my @words = split ' ', $sentence; 
    my $changed; 

    for my $word (@words) { 
     my $eng_word = $lexicon{lc $word}; 
     $eng_word = ucfirst $eng_word if $word =~ /\A[A-Z]/; 
     if ($eng_word) { 
     $word = $eng_word; 
     ++$changed; 
     } 
    } 

    if ($changed) { 
     mkdir $existing_dir unless -d $existing_dir; 
     open my $out_fh, '>>', "$existing_dir/$sentences"; 
     print "@words\n"; 
    } 
    } 
} 
+0

Merci, cela a aidé beaucoup. J'ai vraiment apprécié la façon dont vous avez souligné mes points faibles aussi !! – user3797544

+0

@Borodin J'ai un peu de mal à comprendre l'intention de l'OP. Cependant, il semblait qu'ils voulaient réellement reconstruire la structure de la phrase. Si tel est le cas, une solution regex semble plus appropriée au lieu de diviser par des espaces. 's {(\ w +)} {...} par exemple'. Beau travail sur l'éducation btw. – Miller

Questions connexes