假設我有一個名為 courses.txt 的檔案,其內容如下。該檔案有部分(課程提供者和我使用的電子郵件),然后是各種課程。例如:edX ([email protected]),然后是各種課程名稱,每個課程名稱前面都有序列號。
udemy ([email protected])
"=========================="-
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 ([email protected])
"==========================-"
1) python
2) typescript
3) java concurrency
4) C#
edX ([email protected])
"==========================-"
1) excel
2) scala
3) risk management
4) stock
5) oracle
6) mysql
7) java
==========================-
問題:我想學習一門課程,比如“java”。我想要一個匹配,它顯示匹配的特定行(例如:“java”)和相應的部分名稱(例如,“edX ([email protected])”)。
如果我想搜索“java”,“regex”會給我以下匹配項(我在 Windows 上使用 grep/perl):
<br>
udemy ([email protected])
2) java programming language
coursera ([email protected])
3) java concurrency
edX ([email protected])
7) java
我嘗試了lookbehind/lookahead,但無法弄清楚如何使用電子郵件和課程名稱列印課程提供者名稱。
想法?
uj5u.com熱心網友回復:
如果您在段落中處理(由空行分隔的文本塊),那么在每個段落中匹配所需的模式是相當簡單的 - 標題(后跟帶有='s 的行)和其中的java一行
perl -00 -wnE'say "$1\n$2"
if /(. ?) \n "= . ? \n . ? \n ([^\n] \sjava\s[^\n] )/sx' file
(在 Linux 上測驗;在 Windows 上繼續閱讀。為了便于閱讀,分成幾行。請參閱下面的模式說明。)
在=s 行的末尾,我使用. ?而不是輸入中 s 后面的特定字符,=因為您的示例輸入不一致;它在不同的段落中同時具有-"和。"-適當調整。
由于這是在 Windows 上,您可能必須對"單行使用分隔符(我不知道您使用什么外殼),您可能需要用(hex for ) 替換"模式內的文字,或者甚至簡單地替換為(任何字符)。\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)將其關閉。
uj5u.com熱心網友回復:
我不會給你一個完整的解決方案,但你可以從這個開始:
grep -iE "java|@" filename.txt
一些解釋:
- 使其
-i不區分大小寫 - 使用
-E擴展正則運算式 - 這
|是那些擴展正則運算式的一個例子,它的意思是“或”:顯示包含“java”或“@”的行(后者是所有的電子郵件地址)
結果,您得到一個包含所有電子郵件地址和所有“java”課程的檔案,還有一個問題:如果一行包含電子郵件地址的行后面跟著另一行包含電子郵件地址的行,那么該地址沒有“java”課程。因此,您現在可以使用 Perl 并洗掉下一行也是電子郵件地址的電子郵件地址。
uj5u.com熱心網友回復:
查看輸入資料,我們可以得出結論,該部分以包含電子郵件地址的行開頭。
該部分的資料以序列號開頭。
基于這些資訊,我們可以%sections用包含 email 作為key的 line 構建一個 hash ,并且所有以序列號開頭的 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 ([email protected])
"=========================="-
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 ([email protected])
"==========================-"
1) python
2) typescript
3) java concurrency
4) C#
edX ([email protected])
"==========================-"
1) excel
2) scala
3) risk management
4) stock
5) oracle
6) mysql
7) java
==========================-
<br>
輸出
edX ([email protected])
------------------------------
7) java
coursera ([email protected])
------------------------------
3) java concurrency
udemy ([email protected])
------------------------------
2) java programming language
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/495702.html
