如何检查一行($ _ value)是Perl中的空行?或其他 检查它而不是使用$ _?
的好方法我想像这样编码
if($ _ eq'')#检查当前行是否为空行(没有任何字符) { $ x = 0; }
我使用下面的问题解决方案更新了一些代码。
我的 test.txt 用于解析:
constant fixup private GemAlarmFileName = <A "C:\\TMP\\ALARM.LOG">
vid = 0
name = ""
units = ""
constant fixup private GemConfigAlarms = <U1 0> /* my Comment */
vid = 1
name = "CONFIGALARMS"
units = ""
min = <U1 0>
max = <U1 2>
default = <U1 0>
我的代码如下。
这就是为什么我需要初步设置$ x = 0.我不确定它是否正常 解决与否。
sub ConstantParseAndPrint
{
if (/^$/) // SOLUTION!
{
$x = 0;
}
if ($x == 0)
{
if (/^\s*(constant)\s*(fixup|\/\*fixup\*\/|)\s*(private|)\s*(\w+)\s+=\s+<([a-zA-Z0-9]+)\s+(["']?)([a-zA-Z0-9.:\\]+)\6>\s*(\/\*\s*(.*?)\s*\*\/|)(\r|\n|\s)/)
{
$name1 = $1; # Constant
$name2 = $2; # Fixup
$name3 = $3; # Private
$name4 = $4;
$name5 = $5;
$name6 = $7;
$name7 = $8;
# start print
if (!$name7 eq '')
{
print DEST_XML_FILE "<!-- $name7-->\n";
}
print DEST_XML_FILE " <ECID";
print DEST_XML_FILE " logicalName=\"$name4\"";
print DEST_XML_FILE " valueType=\"$name5\"";
print DEST_XML_FILE " value=\"$name6\"";
$x = 1;
}
}
elsif ($x == 1)
{
if(/\s*vid\s*=\s*(.*?)(\s|\n|\r)/)
{
$nID = $1;
print DEST_XML_FILE " vid=\"$nID\"";
$x = 2;
}
}
elsif ($x == 2)
{
if(/\s*name\s*=\s*(.*?)(\s|\n|\r)/)
{
$nName = $1;
print DEST_XML_FILE " name=$nName";
$x = 3;
}
}
elsif ($x == 3)
{
if (/\s*units\s*=\s*(.*?)(\s|\n|\r)/)
{
$nUnits = $1;
print DEST_XML_FILE " units=$nUnits";
$x = 4;
}
}
elsif ($x == 4)
{
# \s+<([a-zA-Z0-9]+)\s+([a-zA-Z0-9]+)>\
if (/\s*min\s*=\s+<([a-zA-Z0-9]+)\s+([a-zA-Z0-9]+)>(\s|\n|\r)/)
{
#$nMinName1 = $1;
$nMinName2 = $2; # Find the nMin Value
#$nMinName3 = $3;
#$nMinName4 = $4;
print DEST_XML_FILE " min=\"$nMinName2\"";
$x = 5;
}
else
{
print DEST_XML_FILE "></ECID>\n";
$x = 0; # There is no line 4 and line 5
}
}
elsif ($x == 5)
{
if (/\s*max\s*=\s+<([a-zA-Z0-9]+)\s+([a-zA-Z0-9]+)>(\s|\n|\r)/)
{
#$nMaxName1 = $1;
$nMaxName2 = $2; # Find the nMax Value
#$nMaxName3 = $3;
#$nMaxName4 = $4;
print DEST_XML_FILE " max=\"$nMaxName2\"";
$x = 6;
}
}
elsif ($x == 6)
{
if (/\s*default\s*=\s+<([a-zA-Z0-9]+)\s+([a-zA-Z0-9]+)>(\s|\n|\r)/)
{
#$nDefault1 = $1;
$nDefault2 = $2; # Find the default Value
#$nDefault3 = $3;
#$nDefault4 = $4;
print DEST_XML_FILE " default=\"$nDefault2\">";
print DEST_XML_FILE "</ECID>\n";
$x = 0;
}
}
}
答案 0 :(得分:10)
if ($_ =~ /^\s*$/) {
# blank
}
检查由行的开头(\s*
)/ end(^
)绑定的0个或多个空格($
)。那是检查空白行(即可能有空格)。如果您想要空行检查,只需删除\s*
。
对$_
的检查可能是隐式的,因此您可以将上述内容简化为if (/^\s*$/)
以简化。
答案 1 :(得分:7)
反对我更好的判断,我会再次帮助你。
问题不在于如何找到空白行。问题不在于使用哪个正则表达式。根本问题是理解如何分析问题并将分析转化为代码。
在这种情况下,问题是“如何解析此格式?”
我为你写了一个解析器。我还花时间写了我用来编写它的过程的详细描述。
警告:解析器未针对所有情况进行仔细测试。它没有足够的内置错误处理。对于这些功能,您可以请求价目表或自己编写。
以下是您提供的数据样本(我不确定您从中提取了哪些问题):
constant fixup GemEstabCommDelay = <U2 20>
vid = 6
name = "ESTABLISHCOMMUNICATIONSTIMEOUT"
units = "s"
min = <U2 0>
max = <U2 1800>
default = <U2 20>
constant fixup private GemConstantFileName = <A "C:\\TMP\\CONST.LOG">
vid = 4
name = "" units = ""
constant fixup private GemAlarmFileName = <A "C:\\TMP\\ALARM.LOG">
vid = 0
name = ""
units = ""
在为数据文件编写解析器之前,需要先描述文件的结构。如果您使用的是标准格式(比如XML),则可以阅读现有规范。如果您使用的是自制格式,您可以自己编写。
因此,根据样本数据,我们可以看到:
constant
开头。constant
,后跟一个或多个以空格分隔的字词,'='符号和<>
引用的数据值。
constant_name
<>
引用的数据似乎是组合的类型/值说明符。options
。好的,现在我们有一个粗略的规范。我们用它做什么?
格式是如何构建的?考虑从最大到最小的组织逻辑单位。这些将决定我们代码的结构和流程。
因此我们的解析器应该将文件分解为块,然后处理块。
现在我们在评论中粗略地解析了一个解析器:
# Parse a constant spec file.
# Until file is done:
# Read in a whole block
# Parse the block and return key/value pairs for a hash.
# Store a ref to the hash in a big hash of all blocks, keyed by constant_name.
# Return ref to big hash with all block data
现在我们开始填写一些代码:
# Parse a constant spec file.
sub parse_constant_spec {
my $fh = shift;
my %spec;
# Until file is done:
# Read in a whole block
while( my $block = read_block($fh) ) {
# Parse the and return key/value pairs for a hash.
my %constant = parse_block( $block );
# Store a ref to the hash in a big hash of all blocks, keyed by constant_name.
$spec{ $constant{name} } = \%constant;
}
# Return ref to big hash with all block data
return \%spec;
}
但它不起作用。 parse_block
和read_block
潜艇尚未编写。在这个阶段,没关系。关键在于以小的,可理解的块为特征的粗糙。每隔一段时间,为了保持可读性,你需要掩盖子程序中的细节下降 - 否则你最终会遇到无法调试的可怕的1000行潜艇。
现在我们知道我们需要写几个潜艇才能完成,et viola:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my $fh = \*DATA;
print Dumper parse_constant_spec( $fh );
# Parse a constant spec file.
# Pass in a handle to process.
# As long as it acts like a file handle, it will work.
sub parse_constant_spec {
my $fh = shift;
my %spec;
# Until file is done:
# Read in a whole block
while( my $block = read_block($fh) ) {
# Parse the and return key/value pairs for a hash.
my %constant = parse_block( $block );
# Store a ref to the hash in a big hash of all blocks, keyed by constant_name.
$spec{ $constant{const_name} } = \%constant;
}
# Return ref to big hash with all block data
return \%spec;
}
# Read a constant definition block from a file handle.
# void return when there is no data left in the file.
# Otherwise return an array ref containing lines to in the block.
sub read_block {
my $fh = shift;
my @lines;
my $block_started = 0;
while( my $line = <$fh> ) {
$block_started++ if $line =~ /^constant/;
if( $block_started ) {
last if $line =~ /^\s*$/;
push @lines, $line;
}
}
return \@lines if @lines;
return;
}
sub parse_block {
my $block = shift;
my ($start_line, @attribs) = @$block;
my %constant;
# Break down first line:
# First separate assignment from option list.
my ($start_head, $start_tail) = split /=/, $start_line;
# work on option list
my @options = split /\s+/, $start_head;
# Recover constant_name from options:
$constant{const_name} = pop @options;
$constant{options} = \@options;
# Now we parse the value/type specifier
@constant{'type', 'value' } = parse_type_value_specifier( $start_tail );
# Parse attribute lines.
# since we've already got multiple per line, get them all at once.
chomp @attribs;
my $attribs = join ' ', @attribs;
# we have one long line of mixed key = "value" or key = <TYPE VALUE>
@attribs = $attribs =~ /\s*(\w+\s+=\s+".*?"|\w+\s+=\s+<.*?>)\s*/g;
for my $attrib ( @attribs ) {
warn "$attrib\n";
my ($name, $value) = split /\s*=\s*/, $attrib;
if( $value =~ /^"/ ) {
$value =~ s/^"|"\s*$//g;
}
elsif( $value =~ /^</ ) {
$value = [ parse_type_value_specifier( $start_tail ) ];
}
else {
warn "Bad line";
}
$constant{ $name } = $value;
}
return %constant;
}
sub parse_type_value_specifier {
my $tvs = shift;
my ($type, $value) = $tvs =~ /<(\w+)\s+(.*?)>/;
return $type, $value;
}
__DATA__
constant fixup GemEstabCommDelay = <U2 20>
vid = 6
name = "ESTABLISHCOMMUNICATIONSTIMEOUT"
units = "s"
min = <U2 0>
max = <U2 1800>
default = <U2 20>
constant fixup private GemConstantFileName = <A "C:\\TMP\\CONST.LOG">
vid = 4
name = "" units = ""
constant fixup private GemAlarmFileName = <A "C:\\TMP\\ALARM.LOG">
vid = 0
name = ""
units = ""
上述代码远非完美。 IMO,parse_block
太长了,应该被分成更小的潜艇。此外,对形式良好的输入的验证和执行还不够。变量名称和描述可能更清楚,但我并不真正理解数据格式的语义。更好的名称将更接近地匹配数据格式的语义。
尽管存在这些问题,但它确实解析了您的格式并生成了一个非常方便的数据结构,可以填充到您想要的任何输出格式中。
如果您在很多地方使用此格式,我建议将解析代码放入模块中。有关详细信息,请参阅perldoc perlmod。
现在,请停止使用全局变量并忽略好的建议。请开始阅读perldoc,阅读Learning Perl和Perl Best Practices,使用strict,使用警告。当我在阅读阅读清单时,请阅读Global Variables are Bad,然后在维基周围漫步阅读和学习。通过阅读c2,我学到了更多关于编写软件的知识。
如果您对此代码的工作方式有疑问,为什么要按原样布局,可以做出其他选择,说出来并提出问题。我愿意帮助一个自愿的学生。
你的英语很好,但很明显你不是母语。我可能使用了太多复杂的句子。如果你需要用简单的句子写的部分,我可以尝试帮助。我知道用外语工作非常困难。
答案 2 :(得分:6)
答案取决于空白行的含义(除了换行符之外是否包含任何字符,或者它是否只包含空格)。处理此问题的一种惯用方法是使用针对\S
的否定匹配,在这两种情况下都匹配:
if ( ! /\S/ ) {
...
}
如果你只是寻找前者而不是你自己的答案就好了。
您经常会看到此技术用作过滤器:
while (<>) {
next unless /\S/; # Ignore blank lines.
...
}
答案 3 :(得分:5)
您可以使用:
if ($_ =~ /^$/)
甚至只是
if (/^$/)
因为Perl假设检查$_
答案 4 :(得分:2)
如果您只是想检查$_
或$var
的当前值是否为空白(或至少是所有空白行),那么
if (/^\s*$/) { ... }
if ($var =~ /^\s*$/){ ... }
正如其他几位已经提到的那样。
但是,我发现我最常想在循环中处理输入时忽略空行。我这样做:
while (<>) {
next if /^\s*$/;
...
}
如果我想允许传统的shell样式注释,我通常会添加
s/\s*#.*$//;
在检查空行之前。
答案 5 :(得分:1)
while (<>){
chomp;
if ($_ eq ""){
print "blank at $.\n";
}
}
答案 6 :(得分:0)
你展示的方式 - if ( $_ eq '' )
是完全理智的。也许你应该描述一下你的问题是什么?
答案 7 :(得分:0)
if(/^\s*$/)
{
$x = 0;
}