2010-07-28 7 views
0

Je voudrais utiliser Perl pour prendre un fichier de syntaxe SPSS précédemment généré et le formater pour l'utiliser dans un environnement R.Syntaxe de Perl Regex

Ceci est probablement une tâche très simple pour ceux qui sont familiers avec Perl et regex, mais je trébuche.

Les étapes que je les ai Disposées pour ce script Perl sont les suivantes:

  1. Lire dans le fichier SPSS
  2. Trouver des morceaux appropriés de fichier SPSS (regex) pour un traitement ultérieur et le formatage
  3. Traitement supplémentaire noté ci-dessus (plus regex)
  4. Renvoie la syntaxe R à la ligne de commande ou de préférence un fichier.

Le format de base de la syntaxe des étiquettes de valeur SPSS est:

...A bunch of nonsense I do not care about... 
... 
Value Labels 
/gender 
1 "M" 
2 "F" 
/purpose 
1 "business" 
2 "vacation" 
3 "tiddlywinks" 

execute . 
...Resume nonsense... 

et la syntaxe de R désirée Je suis après ressemble:

gender <- as.factor(gender 
    , levels= c(1,2) 
    , labels= c("M","F") 
    ) 
... 

Voici le script Perl je l'ai écrit ainsi loin. J'ai lu avec succès chaque ligne dans le tableau approprié. J'ai le flux général de ce dont j'ai besoin pour la fonction d'impression finale, mais je dois comprendre comment imprimer UNIQUEMENT les tableaux @levels et @labels appropriés pour chaque tableau @vars.

#!/usr/bin/perl 

#Need to change to read from argument in command line 
open(VARVAL, "append.txt"); 
@lines = <VARVAL>; 
close(VARVAL); 

#Read through each line and put into a variable, a value, or a reject 
#I really only want to read in everything between "value labels" and "execute ." 
#That probably requires more regex... 
foreach (@lines){ 
    if ($_ =~ /\//){  #Anything with a/is a variable, remove the/and push 
     $_ =~ tr/\///d; 
     push(@vars, $_) 
    } elsif ($_ =~/\d/) { 
     push(@vals, $_) #Anything that has a number in the line is a value 
     } 
} 
#Splitting each @vals array into levels or labels arrays 
foreach (@vals){ 
    @values = split(/\s+/, $_); #Splitting on a space, vunerable...better to split on first non digit character? 
    foreach (@values) { 
     if ($_ =~/\d/){ 
      push(@levels, $_); 
     } else { 
      push(@labels, $_) 
     } 
    } 
} 

#Get rid of newline 
#I should provavly do this somewhere else? 
chomp(@vars); 
chomp(@levels); 
chomp(@labels); 

#Need to tell it when to stop adding in @levels & @labels. While loop? Hash lookup? 
#Need to get rid of final comma 
#Need to redirect output to a file 
foreach (@vars){ 
    print $_ ." <- as.factor(" . $_ . "\n\t, levels = c(" ; 
     foreach (@levels){ 
      print $_ . ","; 
     } 
    print ")\n\t, labels = c("; 
    foreach(@labels){ 
      print $_ . ","; 
     } 
    print ")\n\t)\n"; 
} 

Et enfin, voici un exemple de sortie du script tel qu'il fonctionne actuellement:

gender <- as.factor(gender 
    , levels = c(1,2,1,2,3,) 
    , labels = c("M","F","biz","action","tiddlywinks",) 
    ) 

je besoin de ceci pour inclure uniquement les niveaux 1,2 et les étiquettes M et F.

Merci pour l'aide!

Répondre

2

Cela semble fonctionner pour moi:

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

my @lines = <DATA>; 

my $current_label = ''; 
my @ordered_labels; 
my %data; 
for my $line (@lines) { 
    if ($line =~ /^\/(.*)$/) { # starts with slash 
     $current_label = $1; 
     push @ordered_labels, $current_label; 
     next; 
    } 
    if (length $current_label) { 
     if ($line =~ /^(\d) "(.*)"$/) { 
      $data{$current_label}{$1} = $2; 
      next; 
     } 
    } 
} 

for my $label (@ordered_labels) { 
    print "$label <- as.factor($label\n"; 
    print " , levels= c("; 
    print join(',',map { $_ } sort keys %{$data{$label}}); 
    print ")\n"; 
    print " , labels= c("; 
    print join(',', 
     map { '"' . $data{$label}{$_} . '"' } 
     sort keys %{$data{$label}}); 
    print ")\n"; 
    print " )\n"; 
} 

__DATA__ 
...A bunch of nonsense I do not care about... 
... 
Value Labels 
/gender 
1 "M" 
2 "F" 
/purpose 
1 "business" 
2 "vacation" 
3 "tiddlywinks" 

execute . 

Et rendements:

gender <- as.factor(gender 
    , levels= c(1,2) 
    , labels= c("M","F") 
    ) 
purpose <- as.factor(purpose 
    , levels= c(1,2,3) 
    , labels= c("business","vacation","tiddlywinks") 
    ) 
+0

Eh bien, je pense qu'il est tout aussi simple que cela. Je dois passer du temps à essayer de digérer ce que tu as fait là-bas, mais je devrais être capable de le comprendre. Merci! – Chase

+0

Pouvez-vous expliquer la deuxième instruction if dans le code ci-dessus? Il semble que "if (longueur $ current_label)" retournera vrai pour chaque ligne, non? Est-ce ce que vous vouliez? Mon interprétation de la ligne suivante est-elle correcte: "if ($ line = ~/^ (\ d)" (. *) "$ /)" Dit "si ma ligne commence par un chiffre, alors saisis tous les caractères dans le "" et les mettre dans la variable $ 1 – Chase

+0

@Chase, il me semble que le second 'if' est destiné à sauter les lignes" tas de non-sens "(en supposant qu'ils ne commencent pas par un'/' Il empêche le code d'enregistrer des valeurs jusqu'à ce qu'il ait trouvé une étiquette valide (notez que $ current_label' est initialisé à la chaîne vide, qui n'a pas de longueur.) Personnellement, j'aurais laissé "$ current_label' non initialisé et ensuite testé La valeur de 'définie $ current_label' à la place, mais cela fonctionne aussi – cjm