簡體   English   中英

Perl / Regex字符串處理多個匹配項

[英]Perl / Regex String Manipulation for multiple matches

我有以下字符串:

<Multicast ID="0/m1" Feed="EUREX-EMDI" IPPort="224.0.50.128:59098" State="CHECK" IsTainted="0" UncrossAfterGap="0" ManualUncrosses="0" AutoUncrosses="0" ExpectedSeqNo="-" />

我需要除去以下內容:

Feed="EUREX-EMDI"
State="CLOSED"
IsTainted="0"

我設法通過以下代碼獲取“ Feed =“ EUREX-EMDI””:

s/^[^Feed]*(?=Feed)//;

所以現在看起來像:

Feed="EUREX-EMDI" IPPort="224.0.50.0:59098" State="CLOSED" IsTainted="0" UncrossAfterGap="0" ManualUncrosses="0" AutoUncrosses="0" ExpectedSeqNo="2191840" />

但是我現在不知道如何在字符串中查找下一部分“ State =“ CLOSED”“,而忽略我已經找到的” Feed =“ EUREX-EMDI”“匹配項

這種事情的perl習慣用法是來自正則表達式捕獲組的多重分配。 假設您始終可以指望感興趣的項目以相同的順序和格式(引用):

($feed, $state, $istainted) = /.*(Feed="[^"]*").*(State="[^"]*").*(IsTainted="[^"]*")/;

或者,如果您只想自己捕獲(未加引號的)值,請更改括號(捕獲組):

($feed, $state, $istainted) = /.*Feed="([^"]*)".*State="([^"]*)".*(IsTainted="([^"]*)"/;

請不要嘗試使用正則表達式解析XML。 很脆 XML是上下文的,而正則表達式則不是。 因此,充其量,這是一個骯臟的駭客,並且可能出於最荒唐的原因而有一天可能在沒有警告的情況下中斷。

請參閱: RegEx匹配除XHTML自包含標記之外的其他開放標記

但是,XML 結構化的,並且實際上很容易使用-只要您使用非常適合該工作的內容:解析器即可。

我喜歡XML::Twig XML::LibXML也很出色,但是學習曲線有些陡峭。 (您還可以獲得類似於正則表達式的XPath ,但更適合XML)

#!/usr/bin/env perl
use strict;
use warnings;

use XML::Twig;
#create a list of what we want to keep. This map just turns it
#into a hash. 
my %keep = map { $_ => 1 } qw ( IsTainted State Feed );

#parse the XML. If it's a file, you may want "parsefile" instead. 
my $twig = XML::Twig->parse( \*DATA );

#iterate the attributes. 
foreach my $att ( keys %{ $twig->root->atts } ) {
   #delete the attribute unless it's in our 'keep' list. 
   $twig->root->del_att($att) unless $keep{$att};
}
#print it. You may find set_pretty_print useful for formatting XML. 
$twig->print;

__DATA__
<Multicast ID="0/m1" Feed="EUREX-EMDI" IPPort="224.0.50.128:59098" State="CHECK" IsTainted="0" UncrossAfterGap="0" ManualUncrosses="0" AutoUncrosses="0" ExpectedSeqNo="-" />

輸出:

<Multicast Feed="EUREX-EMDI" IsTainted="0" State="CHECK"/>

這樣可以保留屬性,並為您提供有效的XML。 但是,如果您想要這些值:

foreach my $att ( qw ( Feed State IsTainted ) ) {
   print $att, "=", $twig->root->att($att),"\n";
}

這將除去所有那些字符串。

$str =~ s/(?s)(?:(?!(?:Feed|State|IsTainted)\\s*=\\s*".*?").)*(?:((?:Feed|State|IsTainted)\\s*=\\s*".*?")|$)/$1/g;

如果要包括空格分隔符,請替換為' $1'
講解

 (?s)                          # Dot - all
 (?:                           # To be removed
      (?!
           (?: Feed | State | IsTainted )
           \s* = \s* " .*? "
      )
      . 
 )*
 (?:                           # To be saved
      (                             # (1 start)
           (?: Feed | State | IsTainted )
           \s* = \s* " .*? "
      )                             # (1 end)
   |  $ 
 )

暫無
暫無

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

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