2010-07-28 5 views
0

Я хотел бы использовать Perl для получения ранее сгенерированного файла синтаксиса SPSS и форматирования его для использования в среде R.Синтаксис Perl Regex

Это, вероятно, очень простая задача для тех, кто знаком с Perl и regex, но я спотыкаюсь.

Шагов, как я изложил их для этого сценария Perl следующим образом:

  1. Читайте в SPSS файл
  2. Найти соответствующие куски SPSS файла (регулярные выражения) для дальнейшей обработки и форматирование
  3. Дальнейшая обработка, отмеченная выше (более регулярное выражение)
  4. Возврат R синтаксиса к командной строке или предпочтительно к файлу.

Основной формат SPSS синтаксиса значений меток:

...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... 

И желаемый синтаксис R я после выглядит как:

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

Вот сценарий Perl я написал, таким образом, далеко. Я успешно прочитал каждую строку в соответствующем массиве. У меня есть общий поток того, что мне нужно для окончательной функции печати, но мне нужно выяснить, как ТОЛЬКО распечатать соответствующие массивы @levels и @labels для каждого массива @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"; 
} 

И, наконец, вот пример вывода из сценария, как он в настоящее время работает:

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

мне это нужно включать только уровни 1,2 и метки M и F.

Спасибо за помощь!

ответ

2

Это, кажется, работает для меня:

#!/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 . 

и выходы:

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

Ну, я думаю, это просто. Мне нужно потратить некоторое время, пытаясь переварить то, что вы там сделали, но я должен уметь это понять. Благодаря! – Chase

+0

Можете ли вы объяснить второй оператор if в приведенном выше коде? Кажется, что «if (length $ current_label)» вернет true для каждой строки, нет? Это то, что вы намеревались? Является ли моя интерпретация следующей строки правильной: «if ($ line = ~/^ (\ d)» (. *) «$ /)« Говорит », если моя строка начинается с цифры, а затем хватайте все и все символы в пределах "" и помещать их в переменную $ 1? – Chase

+0

@Chase, мне кажется, что вторая 'if' предназначена для пропуска« строк бессмыслицы »(предполагая, что они не начинаются с'/'). Это предотвращает регистрацию значений кода до тех пор, пока не найдет действительную метку (обратите внимание, что '$ current_label' инициализируется пустой строкой, длина которой не имеет длины). Лично я бы оставил' $ current_label' неинициализированным, а затем проверял для 'define $ current_label' вместо этого, но это тоже работает. – cjm