【问题标题】:Perl regex syntax generationPerl 正则表达式语法生成
【发布时间】:2010-08-09 18:52:10
【问题描述】:

这是对此处发布的问题的跟进:Perl Regex syntax

讨论的结果产生了这个脚本:

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

基本上,我需要构建 Perl 以适应 SPSS 文件中的语法简写。对于相邻的列,SPSS 允许键入如下内容:

VALUE LABELS
/agree1 to agree5
1 "Strongly disagree"
2 "Disagree"
3 "Neutral"
4 "Agree"
5 "Strongly agree"

由于脚本当前存在,它会生成这个:

agree1 to agree5 <- factor(agree1 to agree5
    , levels= c(1,2,3,4,5,6)
    , labels= c("Strongly disagree","Disagree","Neutral","Agree","Strongly agree","N/A")
    )

我需要它来产生这样的东西:

agree1 <- factor(agree1 
    , levels= c(1,2,3,4,5,6)
    , labels= c("Strongly disagree","Disagree","Neutral","Agree","Strongly agree","N/A")
    )
agree2 <- factor(agree2 
    , levels= c(1,2,3,4,5,6)
    , labels= c("Strongly disagree","Disagree","Neutral","Agree","Strongly agree","N/A")
    )
…

【问题讨论】:

  • 那么您需要帮助来转换现有脚本以生成不同的输出吗?差异似乎很小:您当然应该能够编辑agree1 字符串吗?你能澄清一下你遇到困难的部分吗?
  • 基本上,当 SPSS 语法包含简写 \var1 to varN 时,我需要创建另一个 for 循环。由于它目前存在,当需要为 var1, var2, var3, varN 创建新变量时,脚本将 var1 to varN 视为单个变量
  • Chase:如果你不只是解释你想要什么,而且你自己在哪里遇到困难,你会得到更好的帮助

标签: regex perl spss


【解决方案1】:
use strict;
use warnings;

main();

sub main {
    my @lines = <DATA>;
    my $vlabels = get_value_labels(@lines);
    write_output_delim($vlabels);
}

# Extract the value label information from SPSS syntax.
sub get_value_labels {
    my (@vlabels, $i, $j);
    for my $line (@_){
        if ( $line =~ /^\/(.+)/ ){
            my @vars = parse_var_range($1);
            $i = @vlabels;
            $j = $i + @vars - 1;
            push @vlabels, { var => $_, codes => [] } for @vars;
        }
        elsif ( $line =~ /^\s* (\d) \s+ "(.*)"$/x ){
            push @{$vlabels[$_]{codes}}, [$1, $2] for $i .. $j;
        }
    }
    return \@vlabels;
}

# A helper function to handle variable ranges: "agree1 to agree3".
sub parse_var_range {
    my $vr = shift;
    my @vars = split /\s+ to \s+/x, $vr;
    return $vr unless @vars > 1;

    my ($stem) = $vars[0] =~ /(.+?)\d+$/;
    my @n = map { /(\d+)$/ } @vars;
    return map { "$stem" . $_ } $n[0] .. $n[1];
}

sub write_output_delim {
    my $vlabels = shift;
    for my $vlab (@$vlabels){
        print $vlab->{var}, "\n";
        print join("\t", '', @$_), "\n" for @{$vlab->{codes}}
    }
}

sub write_output_factors {
    # You get the idea...
}

__DATA__
/gender
1 "M"
2 "F"
/purpose
 1 "business"
 2 "vacation"
 3 "tiddlywinks"
/agree1 to agree3
1 "Disagree"
2 "Neutral"
3 "Agree"

【讨论】:

  • @FM - 感谢您的回复。我对 Perl 知识的缺乏显然限制了我在这里,我可以看到所有必要的信息都在这里完成我所追求的。我需要花一些时间来消化你是如何解决这个问题的。我喜欢你将每个主要任务分解成自己的子程序。
猜你喜欢
  • 2014-12-24
  • 2011-03-22
  • 1970-01-01
  • 2014-07-18
  • 2019-07-15
  • 2022-01-14
  • 1970-01-01
  • 2023-03-14
  • 1970-01-01
相关资源
最近更新 更多