如何在 Perl 中使用变量进行替换?
我有几个文本文件,它们曾经是数据库中的表,现在已被反汇编。我正在尝试重新组装它们,一旦我将它们变成可用的形式,这就会很容易。第一个文件“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 文件中的相同键进行匹配,并在键和文本之间放置一个制表符。我确信我忽略了一些非常基本的东西,但我得到的结果看起来与源 .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");
}
}
编辑:为了澄清,结果还应该保留按键中的符号(如果有)。所以它们看起来像:
Sa 1 # Random line of text follows.
Sa 2 This text is just as random.
U 328 #* Continuing text...
I have several text files, that were once tables in a database, which is now disassembled. I'm trying to reassemble them, which will be easy, once I get them into a usable form. The first file, "keys.text" is just a list of labels, inconsistently formatted. Like:
Sa 1 #
Sa 2
U 328 #*
It's always letter(s), [space], number(s), [space], and sometime symbol(s). The text files that match these keys are the same, then followed by a line of text, also separated, or delimited, by a SPACE.
Sa 1 # Random line of text follows.
Sa 2 This text is just as random.
U 328 #* Continuing text...
What I'm trying to do in the code below, is match the key from "keys.text", with the same key in the .txt files, and put a tab between the key, and the text. I'm sure I'm overlooking something very basic, but the result I'm getting, looks identical to the source .txt file.
Thanks in advance for any leads or assistance!
#!/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");
}
}
EDIT: Just to clarify, the results should retain the symbols from the keys as well, if there are any. So they'd look like:
Sa 1 # Random line of text follows.
Sa 2 This text is just as random.
U 328 #* Continuing text...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
对我来说,正则表达式的引用似乎很奇怪。 效果不是
更好吗?
此外,IIRC,
会将换行符保留在 $key 的末尾。chomp $key
来摆脱它。并且不要在
print
参数两边加上括号,尤其是在写入文件句柄时。无论是否正确,它看起来都是错误的,并且会分散人们对真正问题的注意力。The regex seems quoted rather oddly to me. Wouldn't
work better?
Also, IIRC,
<IN1>
will leave the newline on the end of your $key.chomp $key
to get rid of that.And don't put parentheses around your
print
args, esp when you're writing to a file handle. It looks wrong, whether it is or not, and distracts people from the real problems.如果 Perl 不是必须的,你可以使用 awk oneliner
if Perl is not a must, you can use this awk one liner
使用
split
而不是s///
使问题变得简单。在下面的代码中,read_keys
从keys.text
中提取密钥并将它们记录在哈希中。然后,对于在命令行上命名的所有文件(在特殊 Perl 数组 @ARGV 中可用),我们检查每一行以查看它是否以键开头。如果没有,我们就不管它,但否则在键和文本之间插入一个制表符。
请注意,由于 Perl 方便的
-i
选项,我们就地编辑了文件:行
split " ", $_, 3
将当前行精确地分成三个字段。这对于保护可能出现在该行文本部分中的空白是必要的。示例运行:
Using
split
rather thans///
makes the problem straightforward. In the code below,read_keys
extracts the keys fromkeys.text
and records them in a hash.Then for all files named on the command line, available in the special Perl array
@ARGV
, we inspect each line to see whether it begins with a key. If not, we leave it alone, but otherwise insert a TAB between the key and the text.Note that we edit the files in-place thanks to Perl's handy
-i
option:The line
split " ", $_, 3
separates the current line into exactly three fields. This is necessary to protect whitespace that's likely to be present in the text portion of the line.Sample run:
有趣的答案:
其中
(?<=XXXX)
是 XXXX 的零宽度正向后查找。这意味着它匹配紧接着 XXXX,而不是被替换的比赛的一部分。并且:
末尾的
/e
标志表示在填充之前对s///
后半部分的内容进行一次eval
重要说明:我不推荐其中任何一个,它们会混淆程序。但它们很有趣。 :-)
Fun answers:
Where
(?<=XXXX)
is a zero-width positive lookbehind for XXXX. That means it matches just after XXXX without being part of the match that gets substituted.And:
Where the
/e
flag at the end means to do oneeval
of what's in the second half of thes///
before filling it in.Important note: I'm not recommending either of these, they obfuscate the program. But they're interesting. :-)
对每个文件进行两次单独的吸食怎么样?对于第一个文件,您打开密钥并创建初步哈希。对于第二个文件,您所需要做的就是将文本添加到哈希中。
我还没有机会测试它,并且该解决方案对于所有正则表达式似乎有点老套,但可能会让您了解可以尝试的其他方法。
How about doing two separate slurps of each file. For the first file you open the keys and create a preliminary hash. For the second file then all you need to do is add the text to the hash.
I haven't had a chance to test it yet and the solution seems a little hacky with all the regex but might give you an idea of something else you can try.
这看起来是 Perl 中
map
函数的完美位置!将整个文本文件读入数组,然后在整个数组上应用映射函数。您可能想做的唯一一件事是使用quotemeta
函数转义键中任何可能的正则表达式。使用
map
非常高效。我还将密钥读入数组,以便不必在循环中不断打开和关闭密钥文件。这是一个 O^2 算法,但如果你的密钥不是那么大,它应该不会太糟糕。This looks like the perfect place for the
map
function in Perl! Read in the entire text file into an array, then apply the map function across the entire array. The only other thing you might want to do is use thequotemeta
function to escape out any possible regular expressions in your keys.Using
map
is very efficient. I also read the keys into an array in order to not have to keep opening and closing the keys file in my loop. It's an O^2 algorithm, but if your keys aren't that big, it shouldn't be too bad.