簡體   English   中英

如何從Perl中的字符串中提取子字符串?

[英]How can I extract substrings from a string in Perl?

請考慮以下字符串:

1)方案編號: abc-456-hu5t10高優先級 )*****

2)方案編號: frt-78f-hj542w平衡

3)方案ID: 23f-f974-nm54w超級配方運行 )*****

以上述格式等等 - 粗體部分是字符串的變化。

==> 想象一下,我上面有很多格式的字符串。 我想從上面的每個字符串中選擇3個子串(如下面的BOLD所示)。

  • 包含字母數字值的第一個子字符串(例如在它上面的“abc-456-hu5t10”)
  • 包含該單詞的第二個子字符串(例如在其上方的“高優先級”)
  • 包含*的第3個子字符串( IF *出現在字符串ELSE的末尾)

如何從上面顯示的每個字符串中選擇這3個子串? 我知道可以使用Perl中的正則表達式來完成...你能幫忙嗎?

你可以這樣做:

my $data = <<END;
1) Scheme ID: abc-456-hu5t10 (High priority) *
2) Scheme ID: frt-78f-hj542w (Balanced)
3) Scheme ID: 23f-f974-nm54w (super formula run) *
END

foreach (split(/\n/,$data)) {
  $_ =~ /Scheme ID: ([a-z0-9-]+)\s+\(([^)]+)\)\s*(\*)?/ || next;
  my ($id,$word,$star) = ($1,$2,$3);
  print "$id $word $star\n";
}

關鍵是正則表達式:

Scheme ID: ([a-z0-9-]+)\s+\(([^)]+)\)\s*(\*)?

其中分解如下。

固定字符串“Scheme ID:”:

Scheme ID: 

后跟一個或多個字符az,0-9或 - 。 我們使用括號將其捕獲為$ 1:

([a-z0-9-]+)

后跟一個或多個空白字符:

\s+

接下來是一個左括號(我們將其轉義),后跟任意數量的非緊密括號的字符,然后是一個右括號(轉義)。 我們使用未轉義的括號將單詞捕獲為$ 2:

\(([^)]+)\)

隨后是一些空格,可能是*,被捕獲為3美元:

\s*(\*)?

您可以使用正則表達式,如下所示:

/([-a-z0-9]+)\s*\((.*?)\)\s*(\*)?/

例如:

$s = "abc-456-hu5t10 (High priority) *";
$s =~ /([-a-z0-9]+)\s*\((.*?)\)\s*(\*)?/;
print "$1\n$2\n$3\n";

版畫

abc-456-hu5t10
High priority
*
(\S*)\s*\((.*?)\)\s*(\*?)


(\S*)    picks up anything which is NOT whitespace
\s*      0 or more whitespace characters
\(       a literal open parenthesis
(.*?)    anything, non-greedy so stops on first occurrence of...
\)       a literal close parenthesis
\s*      0 or more whitespace characters
(\*?)    0 or 1 occurances of literal *

好吧,這里有一個班輪:

perl -lne 'm|Scheme ID:\s+(.*?)\s+\((.*?)\)\s?(\*)?|g&&print "$1:$2:$3"' file.txt

擴展到一個簡單的腳本來解釋事情好一點:

#!/usr/bin/perl -ln              

#-w : warnings                   
#-l : print newline after every print                               
#-n : apply script body to stdin or files listed at commandline, dont print $_           

use strict; #always do this.     

my $regex = qr{  # precompile regex                                 
  Scheme\ ID:      # to match beginning of line.                      
  \s+              # 1 or more whitespace                             
  (.*?)            # Non greedy match of all characters up to         
  \s+              # 1 or more whitespace                             
  \(               # parenthesis literal                              
    (.*?)            # non-greedy match to the next                     
  \)               # closing literal parenthesis                      
  \s*              # 0 or more whitespace (trailing * is optional)    
  (\*)?            # 0 or 1 literal *s                                
}x;  #x switch allows whitespace in regex to allow documentation.   

#values trapped in $1 $2 $3, so do whatever you need to:            
#Perl lets you use any characters as delimiters, i like pipes because                    
#they reduce the amount of escaping when using file paths           
m|$regex| && print "$1 : $2 : $3";

#alternatively if(m|$regex|) {doOne($1); doTwo($2) ... }     

雖然如果它不是格式化,我會實現一個主循環來處理文件並充實腳本的主體而不是依賴命令行開關進行循環。

很久沒有Perl

while(<STDIN>) {
    next unless /:\s*(\S+)\s+\(([^\)]+)\)\s*(\*?)/;
    print "|$1|$2|$3|\n";
}

這只需要對我的上一個答案做一點改動:

my ($guid, $scheme, $star) = $line =~ m{
    The [ ] Scheme [ ] GUID: [ ]
    ([a-zA-Z0-9-]+)          #capture the guid
    [ ]
    \(  (.+)  \)             #capture the scheme 
    (?:
        [ ]
        ([*])                #capture the star 
    )?                       #if it exists
}x;

字符串1:

$input =~ /'^\S+'/;
$s1 = $&;

字符串2:

$input =~ /\(.*\)/;
$s2 = $&;

字符串3:

$input =~ /\*?$/;
$s3 = $&;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM