- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试解决一个问题,该问题想从文件中显示给定的文本,而忽略特殊字符,并将多行输入修改为仅使用Perl/Regex语言的单格式输出(没有其他语言,如XML, ETC。)。这是我的flight.txt文件中的给定文本:
<start>
<flight number="12345">
<pilot> Holland, Tom</pilot>
<major>Aeronautics Engineer</major>
<company>Boeing</company>
<price>200</price>
<date>06-09-1969</date>
<details>Flight from DC to VA.</details>
</flight>
</start>
Holland, T. "Aeronautics Engineer" 200 06/09/1969 Flight from DC to VA.
-
更改为
/
。
#!/bin/perl
use strict;
use warnings;
my $filename = "flights.txt"
open(my $input, '<:encoding(UTF-8)', $filename)
or die "Could not open file '$filename' $!";
while (my $row = <$input>){
my $text = <>;
$text =~ s/<[^>]*>//g;
print $text;
}
close $input
最佳答案
正如您在对池上的答案的评论中指出的那样,这是您的作业问题:
Create the Perl script “code.pl” that print lines that contain an opening and closing XML heading tag from “flights.txt”. Valid tags are pilot, major, company, price, date, and details regardless of the case. Tags may also have any arbitrary content inside of them. You may assume that a '<' or a '>' character will not appear inside of the attribute's value portion
<start>
和
</start>
或
<flight>
和
</flight>
。您要查找以下行:
<node>...</node>
模式是在行的开头附近有一些您要匹配的字符串,并且该匹配项必须在行的后面显示。我认为您打算执行的任务是练习反向引用。编写好的练习非常困难,而且人们会回过头来熟悉诸如XML之类的东西。我的
Learning Perl Exercises对这个问题比较周到。
...
时,这只是我需要填写的内容,而不是Perl语法(忽略
yada operator,它不能出现在正则表达式中):
use strict;
use warnings;
while( <> ) {
next unless m/ ... /;
print;
}
我将主要忽略该程序结构,而将重点放在匹配运算符
m//
上。当我逐步执行此操作时,请更新模式。
<
开头,以
>
结尾,中间有一些东西。此模式使用
/x
标志使空格无关紧要。我可以展开模式,以便更轻松地查看它:
m/ < ... > /x;
那么尖括号里面有什么呢?在我假装的inputL不是XML的情况下,这些角度内的内容遵循以下规则,如果是XML,则可以在XML标准中阅读这些规则:
xml
开头/i
标志,因此我们免费获得它。
>
之后我将允许的所有字母:
m/ < [a-zA-Z_] ... > /x;
在那之后,我可以有字母和下划线,但现在也有连字符,数字和句点。顺便说一句,许多这样的事情在“标识符”(
ID_Start
)的开头都有一组字符,而对于其余的字符(
ID_Continue
)则有较宽的字符集。 Perl的变量名也有类似的规则。
.
是文字
.
:
m/ < [a-zA-Z_] [a-zA-Z_0-9.-]+ > /x;
通过这种模式,您可以获得比您想要的更多的东西。输出是具有开始标记的每一行。请注意,它与
<flight number="12345">
不匹配,因为此模式不处理属性,这很好,因为我假装这不是XML:
<start>
<pilot> Holland, Tom</pilot>
<major>Aeronautics Engineer</major>
<company>Boeing</company>
<price>200</price>
<date>06-09-1969</date>
<details>Flight from DC to VA.</details>
结束标签与开始标签的名称相同。在我们的输入中,每行有一个开始标记和一个结束标记,并且由于我一次只看一行,因此我可以忽略XML解析器必须关心的许多事情。现在,我将模式分布在几行上,因为
/x
允许我执行此操作,并且
\x
也允许我添加注释,以便记住模式的每个部分的功能。 end标记中的
/
也是匹配运算符分隔符,因此我将其作为
\/
进行了转义:
m/
< [a-zA-Z_] [a-zA-Z_0-9.-]+ > # start tag
... # the interesting text
< \/ ... > # end tag
/x;
我需要填写
...
部分。 “有趣的文字”部分很容易。我会匹配的。
.*
贪婪地匹配零个或多个非换行符:
m/
< [a-zA-Z_] [a-zA-Z_0-9.-]+ > # start tag
.* # the interesting text, greedily
< \/ ... > # end tag
/x;
但是,我真的不希望
*
贪婪。我不希望它与结束标签匹配,因此我可以将非贪婪修饰符
?
添加到
.*
:
m/
< [a-zA-Z_] [a-zA-Z_0-9.-]+ > # start tag
.*? # the interesting text, non-greedily
< \/ ... > # end tag
/x;
现在,我需要填写结束标签的名称部分。它必须与起始名称相同。通过将起始名称括在
(...)
中,我捕获了匹配的字符串部分。这进入捕获缓冲区
$1
。然后,我可以在模式中使用“反向引用”(我想是问题的重点)重复使用该完全匹配。反向引用以
\
开头,并使用您要使用的捕获缓冲区的编号。因此,
\1
使用
$1
中匹配的确切文本;模式不相同,但实际文本匹配:
m/
< # start tag
([a-zA-Z_] [a-zA-Z_0-9.-]+) # $1
>
.*? # the interesting text, non-greedily
< \/ \1 > # end tag
/x;
现在,输出不包含
<start>
,因为它没有结束标签:
<pilot> Holland, Tom</pilot>
<major>Aeronautics Engineer</major>
<company>Boeing</company>
<price>200</price>
<date>06-09-1969</date>
<details>Flight from DC to VA.</details>
如果您修改了数据以将
</date>
更改为
</data>
,那么该行将不匹配,因为开始和结束标记不同。
$2
,并且不会打扰
$1
或
\1
:
m/
< # start tag
([a-zA-Z_] [a-zA-Z_0-9.-]+) # $1
>
( .*? ) # $2, the interesting text, non-greedily
< \/ \1 > # end tag
/x;
但是现在您要打印有趣的测试,而不是整行,因此我将打印
$2
捕获缓冲区,而不是整行。请记住,这些缓冲区仅在成功匹配后才有效,但是我跳过了不匹配的行,所以很好:
use strict;
use warnings;
while( <DATA> ) {
next unless m/
< # start tag
([a-zA-Z_] [a-zA-Z_0-9.-]+) # $1
>
(.*?) # $2, the interesting text, non-greedily
< \/ \1 > # end tag
/x;
print $2;
}
print "\n"; # end all the output!
这使我接近。我在元素之间缺少一些空格(注意
Holland
之前有一个前导空格):
Holland, TomAeronautics EngineerBoeing20006-09-1969Flight from DC to VA.
我可以在每个打印的末尾添加一个空格:
print $2, ' ';
现在您有了输出:
Holland, Tom Aeronautics Engineer Boeing 200 06-09-1969 Flight from DC to VA.
答案可能是
m/ <(.*?)> (.*?) < \/ \1 > /x
作为仅练习反向引用的练习,就可以了。但是,最终您将在处理像这样的真实XML时遇到问题。请注意,
$1
可以捕获所有
flight number="1234"
,因为这并不排除空格或其他不允许的字符。
use strict;
use warnings;
my $pattern = qr/
< # start tag
([a-zA-Z_] [a-zA-Z_0-9.-]+) # $1
>
( .*? ) # the interesting text, non-greedily
< \/ \1 > # end tag
/x;
while( <DATA> ) {
next unless m/$pattern/;
print $2, ' ';
}
这样,
while
循环的机制就与细节有所不同。模式的复杂性不会影响我理解循环的能力。
$1
,这意味着
\1
现在引用了错误的内容。我可以用Perl从Python窃取的
(?<LABEL>...)
功能代替数字,给他们自己的标签。对该标签的反向引用是
\k<LABEL>
:
my $pattern = qr/
< # start tag
(?<tag> # labeled capture
[a-zA-Z_] [a-zA-Z_0-9.-]+
)
>
( .*? ) # the interesting text, non-greedily
< \/ \k<tag> > # end tag
/x;
我什至可以标记“有趣的文字”部分:
my $pattern = qr/
< # start tag
(?<tag>
[a-zA-Z_] [a-zA-Z_0-9.-]+
)
>
(?<text> .*? ) # the interesting text, non-greedily
< \/ \k<tag> > # end tag
/x;
该程序的其余部分仍然有效,因为这些标签是编号捕获变量的别名。但是,我不想依赖于此(因此,标签)。哈希
%+
在标记的捕获中具有值,并且标签是键。有趣的文本在
$+<text>
中:
while( <DATA> ) {
next unless m/$pattern/;
print $+{'text'}, ' ';
}
我忽略的规则
xml
开头。这与XML功能有关,在这里我将忽略。我将更改输入以包括
xmlmeal
节点:
<start>
<flight number="12345">
<pilot> Holland, Tom</pilot>
<xmlmeal> chicken</xmlmeal>
</flight>
</start>
我匹配该
xmlmeal
节点,因为我没有做任何事情来遵循规则。我可以添加否定的超前断言
(?!...)
以排除该断言。作为断言(
\b
和
\A
是其他断言),超前不消耗文本;它不会消耗文本。它只符合条件。我使用
(?!xml)
来表示“无论我现在在哪里,
xml
都不能是下一个”:
my $pattern = qr/
< # start tag
(?<tag>
(?!xml)
[a-zA-Z_] [a-zA-Z_0-9.-]+
)
>
(?<text> .*? ) # the interesting text, non-greedily
< \/ \k<tag> > # end tag
/x;
很好,它不会在输出中显示“chicken”。但是,如果输入的标签名称是
XMLmeal
怎么办?我只排除了小写版本。我需要排除更多:
<start>
<flight number="12345">
<pilot> Holland, Tom</pilot>
<XMLmeal>chicken</XMLmeal>
<xmldrink>diet coke</xmldrink>
<Xmlsnack>almonds</Xmlsnack>
</flight>
</start>
我可以做得更好。我不使用
/i
标志来区分大小写,因为开始和结束标记需要完全匹配。但是,我可以使用
(?i)
为模式的一部分打开不区分大小写的功能,并且所有过去的情况都将忽略大小写:
my $pattern = qr/
< # start tag
(?<tag>
(?i) # ignore case starting here
(?!xml)
[a-zA-Z_] [a-zA-Z_0-9.-]+
)
>
(?<text> .*? ) # the interesting text, non-greedily
< \/ \k<tag> > # end tag
/x;
但是,在分组括号内,
(?i)
仅在该组结束之前有效。我可以限制模式的哪一部分忽略大小写。没有捕获的
(?: ... )
组(因此不会打扰
$1
或
$2
捕获):
(?: (?i) (?!xml) )
现在,我的模式不包括我添加的这三个标签:
my $pattern = qr/
< # start tag
(?<tag>
(?: (?i) (?!xml) ) # not XmL in any case
[a-zA-Z_] [a-zA-Z_0-9.-]+
)
>
(?<text> .*? ) # the interesting text, non-greedily
< \/ \k<tag> > # end tag
/x;
一些魔咒
#!perl
use Mojo::DOM;
my $not_xml = <<~'HERE';
<start>
<flight number="12345">
<pilot> Holland, Tom</pilot>
<major>Aeronautics Engineer</major>
<company>Boeing</company>
<price>200</price>
<date>06-09-1969</date>
<details>Flight from DC to VA.</details>
</flight>
</start>
HERE
Mojo::DOM->new( $not_xml )->xml(1)
->find( 'flight *' )
->map( 'text' )
->each( sub { print "$_ " } );
print "\n";
find
使用CSS选择器来决定要处理的内容。选择器
flight *
是Flight中的所有子节点(因此,任何子标签,无论其名称如何)。
map
在
text
生成的树的每个部分上调用
find
方法,并且
each
输出每个结果。这很简单,因为有人已经完成了所有艰苦的工作。
twig_handlers
中引用的适当子例程。我不会在这里解释特定的Perl功能:
use XML::Twig;
my $twig = XML::Twig->new(
twig_handlers => {
pilot => \&pilot,
major => \&major,
},
);
sub pilot {
my( $twig, $e ) = @_;
my $text = $e->text;
$text =~ s/,\s.\K.*/./;
print $text, ' ';
$twig->purge;
}
sub major {
my( $twig, $e ) = @_;
print '"' . $e->text . '"' . ' ';
$twig->purge;
}
my $xml = <<~'HERE';
<start>
<flight number="12345">
<pilot> Holland, Tom</pilot>
<major>Aeronautics Engineer</major>
<company>Boeing</company>
<price>200</price>
<date>06-09-1969</date>
<details>Flight from DC to VA.</details>
</flight>
</start>
HERE
$twig->parse($xml);
输出:
Holland, T. "Aeronautics Engineer"
现在,您将使用要处理的所有其他内容的子例程完成该操作。
关于regex - 如何在正则表达式的多行中删除特殊字符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62270303/
我正在尝试编写一个函数,该函数接受输入字符串、正则表达式(由 std.regex.regex 从原始字符串生成)和错误消息字符串,并尝试匹配来自使用正则表达式输入字符串,如果没有匹配则显示错误消息。到
-edit- 注意 ?末.{2,}? 我发现你可以写 .{2,}? 是不是和下面一模一样? .{2} 最佳答案 号{2,}表示两次或更多次同时 {2}意思是正好两次。量词默认是贪婪的,所以给定字符串
我有以下文字: This is a test ::a. MODE 3 within 7 hours, ::b. MODE 4 within 13 hours, and ::c. MODE 5 with
我用 Regex.fromLiteral(".*") 创建了一个非常简单的匹配所有正则表达式. 根据documentation :“返回指定文字字符串的文字正则表达式。” 但是我真的不明白“对于指定的
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
该Web项目将静态内容放入一些/content/img文件夹中。 网址规则是:/img/{some md5} 但在文件夹中的位置:/content/img/{前两位数字}/ 例子 url:
我有以下数据: SOMEDATA .test 01/45/12 2.50 THIS IS DATA 我想从中提取数字 2.50。我已设法使用以下 RegEx 做到这一点: (?<=\d{2}\/\d{
我需要证明或反驳下面的正则表达式 (RS + R )* R = R (SR + R)* // or, for programmers: /(RS|R)*R/ == /R(SR|R)*/ 我有一种强烈的
对于具有自由文本的字符串: "The shares of the stock at the XKI Market fell by €89.99 today, which saw a drop of a
例如,我有 RegEx DSX-?2 的 var 我需要将此变量添加到 RegEx 并获取此 .match(/DSX-?2/gi) 最佳答案 您可以创建一个 RegExp对象使用 new RegExp
我无法区分大小写的搜索无法在SQLITE中用于REGEX。支持语法吗? SELECT * FROM table WHERE name REGEXP 'smith[s]*\i' 我希望得到以下答案(假设
Visual Studio / XPath / RegEx: 给定表达式: (?(Car|Car Blue)) +(?.+) +---> +(?.+) 给定搜索字符串: Car Blue Flying
我有一个看起来像这样的正则表达式 /^(?:\w+\s)*(\w+)$*/ 什么是?: ? 最佳答案 它表示子模式是非捕获子模式。这意味着在 (?:\w+\s) 中匹配的任何内容,即使它被 () 括起
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
我在 Excel 工作表(也以 csv 格式)中获得了姓名列表,并根据姓名来源进行了分组。 这就是我创建的组的样子。 现在我想添加一个新列,名称后面包含组名称。 这就是我想要获得的。 我如何得到这个?
我试图将一个字符串拆分为一个字符串列表,单词是分开的,但是周围的字符,例如.. "?()“”!"也分开。 要分隔的字符串是"testing “testing” “one two three” (hi
我有一个来自视频转换文件的完整日志,它看起来像这样: -------------------------------------------------------------------------
在定界符为“-”的模式 X-Y-Z 中,我想检查 Y 是否具有大小 8 而没有重复。 Y 可以是像 Y = (A-B-C) 这样的子集,但如果没有,则 Y 的值为 1 1 - num-12345678
Java确实有这个功能,谢谢你的回答,对我来说失去对API的关注太可惜了... 例如: String strOriginal = "A:B&C@D"; 我认为java中应该有一个非常好的方法来改变它,
我只需要接受符合这些规则的输入... 0.25-24 0.25 的增量(.00、.25、.50、.75) 第一个数字不是必须的。 希望尾随零是可选的。 一些有效条目的示例: 0.25 .50 .5 1
我是一名优秀的程序员,十分优秀!