grep/perl regex查找标题和匹配行



假设我有一个名为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    

我试着向后看/向前看,但不知道如何打印课程提供者的名称、电子邮件和课程名称。

想法吗?

如果您以段落(由空白行分隔的文本块)进行处理,那么在每个段落中,匹配所需的模式是相当简单的-标题(后跟一行='s)和一行java

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

(在Linux上测试;请继续阅读Windows版本。为便于阅读而分成几行。模式的解释见下文。)

=s行末尾,我使用.+?而不是输入中跟随=s的特定字符,因为您的样本输入不一致;它有-""-,在不同的段落。

由于这是在Windows上,您可能必须在一行代码中使用"分隔符(我不知道您使用的是什么shell),因此您可能需要将模式中的文字"替换为x22(十六进制为"),或您喜欢的其他序列。

希望对Windows有好处(现在不能在Windows上测试)

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

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

如果您不介意使用脚本而不是一行代码,那么我推荐的是,例如

use warnings;
use strict;
use feature 'say';
local $/ = "nn";
while (<>) { 
say "$1n$2" 
if /(.+?) n "=+.+? n .+? n ([^n]+ sjavas [^n]+)/sx;
}

,& lt的在操作符逐行读取命令行上给出的文件,但是"line"之前设置为带有local $/ = "nn"的段落。如果这是一个更大的程序的一部分,你不想改变整个程序的$/变量,那么这个局部就是存在的!


或者,不使用使.匹配换行符的/s,而是使用多行模式

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

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

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

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

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

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

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

这里(?s)"打开"/s修饰符,它将一直有效到封闭组的末尾(在本例中是模式的其余部分),但(?-s)将其关闭。

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

grep -iE "java|@" filename.txt

一些解释:

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

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

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

数据从序列号开始。

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

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

注意:要在实际文件中工作,将<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 "$sectionn"
. '-' x 30
. "n$_n" if /b$lookforb/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

最新更新