如何在Perl中使用变量进行替换?

如何在Perl中使用变量进行替换?,perl,variables,substitution,Perl,Variables,Substitution,我有几个文本文件,它们曾经是数据库中的表,现在被反汇编。我正在尝试重新组装它们,一旦我把它们变成可用的形式,这将很容易。第一个文件“keys.text”只是一个标签列表,格式不一致。比如: Sa 1 # Sa 2 U 328 #* 总是字母、[空格]、数字、[空格],有时还有符号。与这些键匹配的文本文件是相同的,然后后跟一行文本,也用空格分隔 Sa 1 # Random line of text follows. Sa 2 This text is just as random. U 328

我有几个文本文件,它们曾经是数据库中的表,现在被反汇编。我正在尝试重新组装它们,一旦我把它们变成可用的形式,这将很容易。第一个文件“keys.text”只是一个标签列表,格式不一致。比如:

Sa 1 #
Sa 2
U 328 #*
总是字母、[空格]、数字、[空格],有时还有符号。与这些键匹配的文本文件是相同的,然后后跟一行文本,也用空格分隔

Sa 1 # Random line of text follows.
Sa 2 This text is just as random.
U 328 #* Continuing text...
在下面的代码中,我试图将“keys.text”中的键与.txt文件中的相同键进行匹配,并在键和文本之间放置一个选项卡。我确信我忽略了一些非常基本的东西,但是我得到的结果,看起来与source.txt文件相同

提前感谢您提供的任何线索或帮助

#!/usr/bin/perl

use strict;
use warnings;
use diagnostics;
open(IN1, "keys.text");

my $key;

# Read each line one at a time
while ($key = <IN1>) {

# For each txt file in the current directory
foreach my $file (<*.txt>) {
  open(IN, $file) or die("Cannot open TXT file for reading: $!");
  open(OUT, ">temp.txt") or die("Cannot open output file: $!");

  # Add temp modified file into directory 
  my $newFilename = "modified\/keyed_" . $file;
  my $line;

  # Read each line one at a time
  while ($line = <IN>) {

     $line =~ s/"\$key"/"\$key" . "\/t"/;
     print(OUT "$line");

  }
  rename("temp.txt", "$newFilename");
 }   
}

对我来说,正则表达式的引用似乎有点奇怪。不会

$line =~ s/$key/$key\t/;
工作得更好

此外,IIRC,
将在$key的末尾保留换行符
咬$key
来摆脱它


不要在
print
args周围加括号,尤其是在写入文件句柄时。不管是不是,它看起来都是错误的,并且会分散人们对真正问题的注意力。

如果Perl不是必须的,那么您可以使用这个awk one liner

$ cat keys.txt
Sa 1 #
Sa 2
U 328 #*

$ cat mytext.txt
Sa 1 # Random line of text follows.
Sa 2 This text is just as random.
U 328 #* Continuing text...

$ awk 'FNR==NR{ k[$1 SEP $2];next }($1 SEP $2 in k) {$2=$2"\t"}1 ' keys.txt mytext.txt
Sa 1     # Random line of text follows.
Sa 2     This text is just as random.
U 328    #* Continuing text...

使用
split
而不是
s//
可以使问题变得简单。在下面的代码中,
read_keys
keys.text
中提取密钥,并将它们记录在散列中

然后,对于命令行上命名的所有文件(在特殊的Perl数组
@ARGV
中可用),我们检查每一行,看它是否以键开头。如果没有,我们就不处理它,但在键和文本之间插入一个制表符

请注意,由于Perl方便的
-i
选项,我们可以就地编辑文件:

-i[延期] 指定要在位编辑由
构造处理的文件。它通过重命名输入文件,以原始名称打开输出文件,并选择该输出文件作为
print
语句的默认值来实现。扩展名(如果提供)用于修改旧文件的名称以制作备份副本

split”“,$\u3
将当前行正好分隔为三个字段。这对于保护行的文本部分中可能存在的空白是必要的

#! /usr/bin/perl -i.bak

use warnings;
use strict;

sub usage { "Usage: $0 text-file\n" }

sub read_keys {
  my $path = "keys.text";
  open my $fh, "<", $path
    or die "$0: open $path: $!";

  my %key;
  while (<$fh>) {
    my($text,$num) = split;
    ++$key{$text}{$num} if defined $text && defined $num;
  }

  wantarray ? %key : \%key;
}

die usage unless @ARGV;
my %key = read_keys;

while (<>) {
  my($text,$num,$line) = split " ", $_, 3;
  $_ = "$text $num\t$line" if defined $text &&
                              defined $num &&
                              $key{$text}{$num};
  print;
}
#/usr/bin/perl-i.bak
使用警告;
严格使用;
子用法{“用法:$0文本文件\n”}
分读键{
my$path=“keys.text”;
打开我的$fh,“有趣的答案:

$line =~ s/(?<=$key)/\t/;
其中末尾的
/e
标志意味着在填写前对
s///
的后半部分进行一次
评估


重要提示:我不推荐这两种方法中的任何一种,它们会混淆程序。但它们很有趣。:-

对每个文件执行两个单独的slurp如何。对于第一个文件,您打开密钥并创建一个初步哈希。对于第二个文件,您只需将文本添加到哈希中

use strict;
use warnings;

my $keys_file = "path to keys.txt";
my $content_file = "path to content.txt";
my $output_file = "path to output.txt";

my %hash = ();

my $keys_regex = '^([a-zA-Z]+)\s*\(d+)\s*([^\da-zA-Z\s]+)';

open my $fh, '<', $keys_file or die "could not open $key_file";
while(<$fh>){
    my $line = $_;
    if ($line =~ /$keys_regex/){
        my $key = $1;
        my $number = $2;
        my $symbol = $3;
        $hash{$key}{'number'} = $number;
        $hash{$key}{'symbol'} = $symbol;
    }
}
close $fh;

open my $fh, '<', $content_file or die "could not open $content_file";
while(<$fh>){
    my $line = $_;
    if ($line =~ /^([a-zA-Z]+)/){
        my $key = $1;
// strip content_file line from keys/number/symbols to leave text
        line =~ s/^$key//;
        line =~ s/\s*$hash{$key}{'number'}//;
        line =~ s/\s*$hash{$key}{'symbol'}//;
        $line =~ s/^\s+//g;
        $hash{$key}{'text'} = $line;
    }
}
close $fh;

open my $fh, '>', $output_file or die "could not open $output_file";
for my $key (keys %hash){
    print $fh $key . " " . $hash{$key}{'number'} . " " . $hash{$key}{'symbol'} . "\t" . $hash{$key}{'text'} . "\n";
}
close $fh;
使用严格;
使用警告;
my$keys_file=“path to keys.txt”;
my$content\u file=“path to content.txt”;
my$output\u file=“path to output.txt”;
我的%hash=();
我的$keys\u regex='^([a-zA-Z]+)\s*\(d+)\s*([^\da-zA-Z\s]+);
打开我的$fh、、$output_文件或die“无法打开$output_文件”;
对于我的$key(key%散列){
打印$fh$key。“$hash{$key}{'number'}.”“$hash{$key}{'symbol'}.”\t“$hash{$key}{'text'}.”\n”;
}
收盘价$fh;

我还没有机会测试它,解决方案似乎对所有的正则表达式都有点不成熟,但可能会给你一个可以尝试的其他方法的想法。

这看起来是Perl中
map
函数的最佳位置!将整个文本文件读入一个数组,然后在整个数组中应用map函数。唯一的方法是r您可能要做的事情是使用
quotemeta
函数来转义键中任何可能的正则表达式

使用
map
非常有效。我还将密钥读入数组,以便不必在循环中不断打开和关闭密钥文件。这是一种O^2算法,但如果密钥没有那么大,应该不会太糟糕

#! /usr/bin/env perl

use strict;
use vars;
use warnings;

open (KEYS, "keys.text")
    or die "Cannot open 'keys.text' for reading\n";
my @keys = <KEYS>;
close (KEYS);

foreach my $file (glob("*.txt")) {
    open (TEXT, "$file")
        or die "Cannot open '$file' for reading\n";
    my @textArray = <TEXT>;
    close (TEXT);

    foreach my $line (@keys) {
        chomp $line;
        map($_ =~ s/^$line/$line\t/, @textArray);
    }
    open (NEW_TEXT, ">$file.new") or
        die qq(Can't open file "$file" for writing\n);

    print TEXT join("\n", @textArray) . "\n";
close (TEXT);
}
!/usr/bin/env perl
严格使用;
使用变量;
使用警告;
打开(键,“键.文本”)
或死“无法打开”键。文本“用于读取\n”;
我的@keys=;
关闭(钥匙);
foreach my$文件(glob(“*.txt”)){
打开(文本“$file”)
或“无法打开“$file”进行读取\n”;
我的@textArray=;
关闭(文本);
foreach my$行(@keys){
chomp$行;
映射($u=~ s/^$line/$line\t/,@textArray);
}
打开(新文本“>$file.NEW”)或
死qq(无法打开文件“$file”进行写入\n);
打印文本联接(“\n”,@textary)。“\n”;
关闭(文本);
}

对我自己的答案发表评论:不必循环写入文件,你可以执行一次连接并立即写入整个内容。我将编辑我的命令以显示。我猜你的输出与你的输入相同,因为你的正则表达式与任何内容都不匹配。请查看下面赵的答案以解决此问题。如果你知道每个“数据”文件都将启动有了这个键,你就不能在不知道键的情况下插入标签吗?这个键将始终匹配/\w+\s\w+\s[*|#]*/或者[*|#]]中的任何其他内容?
$line =~ s/$key/$key . "\t"/e;
use strict;
use warnings;

my $keys_file = "path to keys.txt";
my $content_file = "path to content.txt";
my $output_file = "path to output.txt";

my %hash = ();

my $keys_regex = '^([a-zA-Z]+)\s*\(d+)\s*([^\da-zA-Z\s]+)';

open my $fh, '<', $keys_file or die "could not open $key_file";
while(<$fh>){
    my $line = $_;
    if ($line =~ /$keys_regex/){
        my $key = $1;
        my $number = $2;
        my $symbol = $3;
        $hash{$key}{'number'} = $number;
        $hash{$key}{'symbol'} = $symbol;
    }
}
close $fh;

open my $fh, '<', $content_file or die "could not open $content_file";
while(<$fh>){
    my $line = $_;
    if ($line =~ /^([a-zA-Z]+)/){
        my $key = $1;
// strip content_file line from keys/number/symbols to leave text
        line =~ s/^$key//;
        line =~ s/\s*$hash{$key}{'number'}//;
        line =~ s/\s*$hash{$key}{'symbol'}//;
        $line =~ s/^\s+//g;
        $hash{$key}{'text'} = $line;
    }
}
close $fh;

open my $fh, '>', $output_file or die "could not open $output_file";
for my $key (keys %hash){
    print $fh $key . " " . $hash{$key}{'number'} . " " . $hash{$key}{'symbol'} . "\t" . $hash{$key}{'text'} . "\n";
}
close $fh;
#! /usr/bin/env perl

use strict;
use vars;
use warnings;

open (KEYS, "keys.text")
    or die "Cannot open 'keys.text' for reading\n";
my @keys = <KEYS>;
close (KEYS);

foreach my $file (glob("*.txt")) {
    open (TEXT, "$file")
        or die "Cannot open '$file' for reading\n";
    my @textArray = <TEXT>;
    close (TEXT);

    foreach my $line (@keys) {
        chomp $line;
        map($_ =~ s/^$line/$line\t/, @textArray);
    }
    open (NEW_TEXT, ">$file.new") or
        die qq(Can't open file "$file" for writing\n);

    print TEXT join("\n", @textArray) . "\n";
close (TEXT);
}