繁体   English   中英

用于查找标题和匹配行的 grep/perl 正则表达式

[英]grep/perl regex for finding a header and a matching line

假设我有一个名为 courses.txt 的文件,其内容如下。 该文件有部分(课程提供者和我使用的电子邮件),然后是各种课程。 例如:edX (anjan.fizz@gmail.com),然后是各种课程名称,每个课程名称前面都有序列号。

udemy (anjan.bar@gmail.com)  
"=========================="-  
1) foo bar
2) java programming language
3) redis stephen grider
4) javascript
5) react with typescript
6) kotlin
7) Etherium and Solidity : the Complete Developer's Guide
8) reactive programming with spring  


coursera (anjan.foo@gmail.com)  
"==========================-"  
1) python
2) typescript
3) java concurrency
4) C#

edX (anjan.fizz@gmail.com)  
"==========================-"  
1) excel
2) scala
3) risk management
4) stock
5) oracle
6) mysql  
7) java  
==========================-    

问题:我想学习一门课程,比如“java”。 我想要一个匹配,它显示匹配的特定行(例如:“java”)和相应的部分名称(例如,“edX (anjan.fizz@gmail.com)”)。

如果我想搜索“java”,“regex”会给我以下匹配项(我在 Windows 上使用 grep/perl):

  <br>
udemy (anjan.bar@gmail.com)    
2) java programming language  

coursera (anjan.foo@gmail.com)  
3) java concurrency

edX (anjan.fizz@gmail.com)    
7) java    

我尝试了lookbehind/lookahead,但无法弄清楚如何使用电子邮件和课程名称打印课程提供者名称。

想法?

如果您在段落中处理(由空行分隔的文本块),那么在每个段落中匹配所需的模式是相当简单的 - 标题(后面是带有=的行)和其中带有java的行

perl -00 -wnE'say "$1\n$2" 
    if /(.+?) \n "=+.+? \n .+? \n ([^\n]+\sjava\s[^\n]+)/sx' file

(在 Linux 上测试;在 Windows 上继续阅读。为了便于阅读,分成几行。请参阅下面的模式说明。)

在带有= s 的行的末尾,我使用.+? 而不是输入中= s 后面的特定字符,因为您的示例输入不一致; 它在不同的段落中同时具有-""- 适当调整。

由于这是在 Windows 上,您可能必须使用"分隔符作为单行符(我不知道您使用什么外壳),您可能需要用\x22替换模式内的文字" (十六进制表示" ) ,或您喜欢的其他序列。

希望对 Windows 有好处(目前无法在 Windows 上测试)

perl -00 -wnE "say qq($1\n$2) 
    if /(.+?)\n \x22=+.+? \n .+? \n ([^\n]+\sjava\s[^\n]+) /sx
" file

-00 开关使它在段落中阅读。 使用/x修饰符,模式中的空格被忽略,因此我们可以使用它们来分隔内容以提高可读性。 使用/s修饰符将. 也匹配换行符。 这对中间很重要.+? 匹配多行,最多包含java的一行(由空格包围)。

如果您不介意使用脚本而不是单行符,那么我建议您这样做,例如

use warnings;
use strict;
use feature 'say';

local $/ = "\n\n";

while (<>) { 
    say "$1\n$2" 
        if /(.+?) \n "=+.+? \n .+? \n ([^\n]+ \sjava\s [^\n]+)/sx;
}

<> 操作符逐行读取命令行中给出的文件,但“行”的概念之前设置为带有local $/ = "\n\n"的段落。 如果这是一个较大程序的一部分,而您不想更改整个程序的$/ 变量,那么该本地就在那里!


或者,而不是使用/s来生成. 匹配换行符,对多行使用一个模式

perl -00 -wnE'say "$1\n$2" 
    if /(.+) \n "=+.+ \n (?:.+\n)* (.+\sjava\s.+)/x' file

或者,如果您在 Windows 上需要"..." ,例如

perl -00 -wnE "say qq($1\n$2) 
    if /(.+) \n \x22=+.+ \n (?:.+\n)* (.+\sjava\s.+)/x' file

(同样,我现在无法在 Windows 上进行测试。)

请注意,现在我们不必使所有这些.+不贪心添加? ( .+? ) 就像上面带有/s的模式一样——现在.+停在换行符处,就像这里需要的那样。

或者,通过扩展模式动态使用/s修饰符

perl -00 -wnE "say "$1\n$2" 
    if /(.+) \n \x22=+.+ \n (?s).+?(?-s) (.+\sjava\s.+)/x
" file

这里(?s) “打开” /s修饰符,该修饰符将一直有效,直到封闭组结束(在这种情况下为模式的其余部分),但(?-s)将其关闭。

我不会给你一个完整的解决方案,但你可以从这个开始:

grep -iE "java|@" filename.txt

一些解释:

  • -i使其不区分大小写
  • -E使用扩展的正则表达式
  • | 是那些扩展正则表达式的一个例子,它的意思是“或”:显示包含“java”或“@”的行(后者是所有的电子邮件地址)

结果,您会得到一个包含所有电子邮件地址和所有“java”课程的文件,还有一个问题:如果一行带有电子邮件地址的行后面跟着另一行带有电子邮件地址的行,那么该地址没有“java”课程。 因此,您现在可以使用 Perl 并删除下一行也是电子邮件地址的电子邮件地址。

查看输入数据,我们可以得出结论,该部分以包含电子邮件地址的行开头。

该部分的数据以序列号开头。

基于这些信息,我们可以用包含 email 作为key的 line 构建一个 hash %sections ,并且所有以序列号开头的 line 都可以存储在 key 下的数组中。

构建哈希后,代码将遍历所有部分并查找包含搜索词的行,如果该词找到与匹配的输出部分

注意:要处理真实文件,将<DATA>替换为<>然后运行为./script.pl filename.dat

use strict;
use warnings;
use feature 'say';

my($lookfor, %sections, $key);

$lookfor = shift || die "Provide search term";

while( <DATA> ) {
    chomp;
    $key = $_ if /@/;
    push @{$sections{$key}}, $_ if /^\d\) /;
}

for my $section (keys %sections ) {
    for( @{$sections{$section}} ) {
        say "$section\n"
          . '-' x 30
          . "\n$_\n" if /\b$lookfor\b/i;
    }
}

exit 0;

__DATA__
udemy (anjan.bar@gmail.com)  
"=========================="-  
1) foo bar
2) java programming language
3) redis stephen grider
4) javascript
5) react with typescript
6) kotlin
7) Etherium and Solidity : the Complete Developer's Guide
8) reactive programming with spring  


coursera (anjan.foo@gmail.com)  
"==========================-"  
1) python
2) typescript
3) java concurrency
4) C#

edX (anjan.fizz@gmail.com)  
"==========================-"  
1) excel
2) scala
3) risk management
4) stock
5) oracle
6) mysql  
7) java  
==========================-    
<br>

输出

edX (anjan.fizz@gmail.com)
------------------------------
7) java

coursera (anjan.foo@gmail.com)
------------------------------
3) java concurrency

udemy (anjan.bar@gmail.com)
------------------------------
2) java programming language

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM