7

基本上,这是我在过去半小时内使用 Google 进行编程并试图实现一个简单的事情的结果:从中获取用户输入STDIN并将其写入结构化 XML 文件作为输出。下面是我丑陋的代码:

#!/bin/perl
print "img URL = ?    ";
$img = <>;
chomp($img);
print "filename = ?    ";
$filename = <>;
chomp($filename);

# now write xml with inserted contents to a file:
open (CARDFILE, ">>$filename");
print CARDFILE "<card>\r\n";
print CARDFILE "    <img>$img</img>\r\n";
print CARDFILE "    <type>$type</type>\r\n";
print CARDFILE "    <expansion>$expansion</expansion>\r\n";
print CARDFILE "    <keyword>$keyword</keyword>\r\n";
print CARDFILE "    <color>$color</color>\r\n";
print CARDFILE "    <linkcolor>$linkcolor</linkcolor>\r\n";
print CARDFILE "    <kickercolor>$kickercolor</kickercolor>\r\n";
print CARDFILE "    <cost>$cost</cost>\r\n";
print CARDFILE "    <strength>$strength</strength>\r\n";
print CARDFILE "    <health>$health</health>\r\n";
print CARDFILE "</card>";
close (CARDFILE);  

我是 Perl 新手,但我可以说出我的代码中的一些重大问题:

  1. 使用两行首先接收STDIN然后chomp()它摆脱尾随回车。应该有单行吗?

  2. 我无法弄清楚如何使用“here-doc”来一次性打印多行文件。如果没有CARDFILE文件句柄,我可以使用 here-doc 语法将所有字符串打印到STDOUT单个打印语句中。现在我必须多次调用打印函数。

  3. 对于这些"\r\n"s,有没有办法使用不同的功能,所以我不必记住在每行之后手动插入它们?

4

4 回答 4

11

读一行

阅读单行的成语是

chomp(my $var = <>);

但我通常最终会编写一个小子prompt程序:

sub prompt {
  print @_;
  chomp(my $answer = <>);
  return $answer;
}
...;
my $img = prompt("img URL = ? ");

这里文档

here-doc 只是另一种字符串文字,例如

my $str = <<"END";
foo bar
baz
END
print $str;

如果用单引号括住分隔符: <<'END',则不能将变量插入到 here-doc 中。请注意,结束标记必须始终位于行首,但可能包含空格字符:

    my $string = <<'END THIS';
    foo
    bar
END THIS
    # marker must be at start of line!

您可以直接打印here-doc,例如

print CARDFILE <<"END";
<card>
    <img>$img</img>
    <type>$type</type>
    <expansion>$expansion</expansion>
    <keyword>$keyword</keyword>
    <color>$color</color>
    <linkcolor>$linkcolor</linkcolor>
    <kickercolor>$kickercolor</kickercolor>
    <cost>$cost</cost>
    <strength>$strength</strength>
    <health>$health</health>
</card>
END

不同之处在于行尾将没有\r\n,除非您使用 Windows 行结尾保存源文件。但是,here-doc 确实包含物理换行符,并且总是以换行符结束。

打印东西

print函数打印由特殊变量分隔的参数$,,然后输出该$\变量。默认情况下,这两个都是空的。但我们可以提供一个临时值:

local $\ = "123";
print "foo";

输出:

foo123

当然,我们通常会将其设置为\n. 但是有一个捷径:只要在源代码的开头加上一个use feature 'say'或(或更高),就可以了use 5.010

say "foo";

它会自动附加一个换行符。

打开文件句柄

使用词法变量。使用三个参数打开。进行适当的错误处理。这意味着:

use autodie;
open my $fh, "<", "filename";

或者

my $filename = "filename";
open my $fh, "<", $filename or die "Can't open $filename: $!";

第二个参数是mode>>用于追加。明确指定它更安全,而不是作为文件名的一部分。

一般说明

始终use strict; use warnings;位于脚本的顶部,这有助于发现问题。

于 2013-07-05T00:18:42.077 回答
8

人们对 Perl 中的here 文件的最大问题是他们忘记了行尾的分号。

这里的文件有两种形式。如果您在此处的文档名称周围使用双引号(或不使用),它将插入变量等。

如果您在 Here Document 名称周围使用单引号,则不会进行插值。仔细观察分号和引号的位置。

#! /usr/bin/env perl
#
use warnings;
use strict;
use feature qw(say);

my $foo = "The value of foo";
my $bar = "The value of bar";

my $heredoc =<<"END_HERE_1";
This is my first here document
and this will interpolate things
like $foo and $bar.

Heck, it even shows up correctly
in Vim.
END_HERE_1

say "$heredoc"; # All set

print  <<'END_HERE_2';
This is my first here document
and this will NOT interpolate things
like $foo and $bar.

Heck, it even shows up correctly
in Vim.
END_HERE_2

say "And that's all folks!";
于 2013-07-05T00:05:52.070 回答
3

如果你想要一个here-document,你可以使用:

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

print "img URL = ?    ";
chomp(my $img = <>);
print "filename = ?   ";
chomp(my $filename = <>);

# now write xml with inserted contents to a file:
open my $CARDFILE, ">>", $filename or die "Failed to open file $filename for writing";
my $type = "unregimented";
my $expansion = "contracted";
my $keyword = "lock";
my $color = "green";
my $linkcolor = "blue";
my $kickercolor = "red";
my $cost = '$0.00';
my $strength = "humungous";
my $health = "excellent";

print $CARDFILE <<EOF;
<card>\r
    <img>$img</img>\r
    <type>$type</type>\r
    <expansion>$expansion</expansion>\r
    <keyword>$keyword</keyword>\r
    <color>$color</color>\r
    <linkcolor>$linkcolor</linkcolor>\r
    <kickercolor>$kickercolor</kickercolor>\r
    <cost>$cost</cost>\r
    <strength>$strength</strength>\r
    <health>$health</health>\r
</card>\r
EOF

close $CARDFILE;

注意压缩后的输入,数据现在垂直排列——尽管运行 Perl 脚本几次,我宁愿它从命令行参数中获取数据,而不是提示输入它。

具有讽刺意味的是,如果您使用 here 文档,则无法使用输出记录分隔符来指定行尾。无需做任何特别的事情,您可以设置:

$\ = "\r\n";

并且每个print输出都将以 CRLF 结束。(默认值为,因此默认情况下$\不会undef以行结尾打印任何内容。)或者,您可以通过以下方式使您的代码更易于理解:

use English '-no_match_vars';

$ORS = "\r\n";

例如:

#!/usr/bin/env perl
use strict;
use warnings;
use English '-no_match_vars';

print "img URL = ?    ";
my $img = <>;
chomp($img);
print "filename = ?    ";
my $filename = <>;
chomp($filename);

# now write xml with inserted contents to a file:
open my $CARDFILE, ">>", $filename or die "Failed to open file $filename for writing";
my $type = "unregimented";
my $expansion = "contracted";
my $keyword = "lock";
my $color = "green";
my $linkcolor = "blue";
my $kickercolor = "red";
my $cost = '$0.00';
my $strength = "humungous";
my $health = "excellent";

$ORS = "\r\n";

print $CARDFILE "<card>";
print $CARDFILE "    <img>$img</img>";
print $CARDFILE "    <type>$type</type>";
print $CARDFILE "    <expansion>$expansion</expansion>";
print $CARDFILE "    <keyword>$keyword</keyword>";
print $CARDFILE "    <color>$color</color>";
print $CARDFILE "    <linkcolor>$linkcolor</linkcolor>";
print $CARDFILE "    <kickercolor>$kickercolor</kickercolor>";
print $CARDFILE "    <cost>$cost</cost>";
print $CARDFILE "    <strength>$strength</strength>";
print $CARDFILE "    <health>$health</health>";
print $CARDFILE "</card>";

close $CARDFILE;
于 2013-07-05T00:19:28.757 回答
0

你可以做

print CARDFILE qq{<card>
<img>$img</img>
<type>$type</type>};

等等。qq告诉 Perl 对字符串进行插值,因此它与执行“多行字符串”相同。

于 2013-07-04T23:56:47.960 回答