Perl Learning 8 Processing Text with Regular Expression

來源:互聯網
上載者:User

標籤:

用s///進行替換:如果把m//模式比對(pattern match)想象成文文書處理器的“尋找”功能,那麼s///替換(substitution)操作符就是“尋找並替換”功能。此操作符只是把存在變數中匹配模式的那部分內容替換成另一個字串:

<span style="font-size:18px;">$_ = "He's out bowling with Barney tonigth.";s/Barney/Fred/; #replacing Barney with Fredprint "$_\n";</span>

如果匹配失敗,則什麼事都不會發生,變數也不會受影響。當然,模式字串與替換字串還可以更加複雜。下面的替換字串用到了第一個捕獲的變數,也就是$1,模式比對時會對它賦值:

<span style="font-size:18px;">s/with (\w+)/against $1's team/;print "$_\n"; #print “He’s out bowling against Fred’s team tonight.”</span>

S///返回的是布爾值,替換成功時為真,否則為假。

 

用/g進行全域替換,s///只會進行一次替換,/g修飾符可以讓s///進行所有可能的,不重複的替換:

<span style="font-size:18px;">$_ = “home, sweet home !”;s/home/cave/g;print “$_\n”; #print “cave, sweet cave!”</span>

一個相當常見的全域替換就是縮減空白,也就是將任何連續的空白轉換為單一空格:

<span style="font-size:18px;">$_ = “Input   data\t may have    extra whitespace.”;s/\s+/ /g; #”Input data may have extra whitespace.”</span>

大小寫替換:\U轉義符會將其後的所有字元轉換成大寫的:

<span style="font-size:18px;">$_ = “I saw Barney with Fred.”;s/(fred|barney)/\U$1/gi; # “I saw BARNEY with FRED.”</span>

類似地,\L轉義符會將它後面的所有字元轉換成小寫。預設情況下,它們會影響之後全部的(替換)字串。你也可以用\E關閉大小寫轉換的功能:

<span style="font-size:18px;">s/(\w+) with (\w+)/\U$2\E with $1/i;  #”I saw FRED with Barney.”</span>

split操作符,用法:my @fields = split /separator/, $string;

這裡的split操作符用拆分模式掃描指定的字串並返回欄位(也就是子字串)列表。期間只要模式在某處匹配成功,該處就是當前欄位的結尾、下一個欄位的開頭。split會保留開頭處的空欄位,卻會捨棄結尾處的空欄位。

預設split會以空白符分隔$_中的字串: my @fields = split; # split /\s+/, $_;

 

join函數不會使用模式,它的功能與split恰好相反。用法: my $result = join $glue, @pieces; 我們可以把join的第一個參數理解為膠水,它可以是任一字元串。其餘參數則是一串片段。join會把膠水塗進每個片段之間並返回結果字串:

my $x = join “:”, 4,6, 8, 10, 12; # $x為”4:6:8:10:12”

所以說,列表至少要有兩個元素,否則膠水無法塗進去。

 

列表上下文中的m//,在使用split時,模式指定的只是分隔字元:分解得到的欄位未必就是我們需要的資料。有時候,指定想要留下的部分反而比較簡單。之前在s///的例子中看到的/g修飾符同樣也可以用在m//操作符上,其效果就是讓模式能夠匹配到字串中的多個地方。

<span style="font-size:18px;">my $text = “Fred dropped a 5 ton granite block on Mr. Slate”;my @words = ($text =~/([a-z]+)/ig);print “Result: @words\n”;# print : Fred dropped a ton granite block on Mr Slate</span>

這就好比是反過來用split:正則模式指定的並非想要去除的部分,反而是要留下的部分。

事實上,如果模式中有多組圓括弧,那麼每次匹配就能捕獲多個字串。假設我們想把一個字串變成雜湊,就可以這樣做:

my $data = “Barney Rubble Fred Flintstone Wilma Flintstone”; my %last_name = ($data =~ /(\w+)\s+(\w+)/g);

每次模式比對成功就會返回一對被捕獲的值,而這一對值正好成為新雜湊的鍵值對。

 

非貪婪量詞。Regex引擎一直進行回溯動作,不斷地以不同的方式調整模式比對的內容來適應字串,直到最終找到一個整體匹配成功的為止,要是直到最後都找不到就宣告失敗。

 

跨行的模式比對, ^和$都是代表整個字串的開頭和結尾的錨位。但當模式加上/m修飾符之後,就可以用它們匹配字串內的每一行,這樣一來,它們代表的位置就不再是整個字串的頭尾,而是每行的開頭跟結尾了。接下來的程式會先把整個檔案讀進一個變數,然後把檔案名稱作為每一行的首碼進行替換:

<span style="font-size:18px;">$fliename = "hsl.txt";open FILE, $flienameor die "Can't open '$fliename' : $!";my $lines = join '',<FILE>;$lines =~s/^/$fliename: /gm;print $lines;</span>

一次更新多個檔案:通過程式自動更新檔案內容時,最常見的做法就是先開啟一個和原來內容一致的新檔案,然後在需要的位置進行改寫,最後把修改後的內容寫進去。

現在有個叫做fred03.dat的檔案內容如下:

需要改為:

簡單的說,我們需要作出三項改動:Author欄位的姓名要改,Date要改為今天的日期,而Phone要刪除。

<span style="font-size:18px;">#!/usr/bin/perl -wuse strict;chomp(my $date = localtime);$^I = "f.bak";while(<>){s/^Author:.*/Author: Randal L. Schwartz/;s/^Phone:.*\n//;s/^Date:.*/Date: $date/;print;}</span>

在命令列中輸入:perl change.pl fred03.dat

先假設鑽石操作符正好開啟了檔案fred03.dat。除了像以前一樣開啟檔案之外,他還會把檔案名稱改為fred03.dat.bak。雖然開啟的是同一個檔案,但是它在磁碟上的檔案名稱已經不同了。接著,鑽石操作符會開啟一個新檔案並將它取名為fred03.dat。這麼做並不會有任何問題,因為我們已經沒有同名檔案了。現在鑽石操作符會把預設的輸出設定為這個新開啟的檔案,所以輸出來的所有內容都會被寫進這個檔案。

習題:



1.我的:

<span style="font-size:18px;">use strict;chomp(my $what = <STDIN>);print "$what" x 3;</span>

答案:/($what){3}/表示沒有看懂

2

<span style="font-size:18px;">my $in = $ARGV[0];if(! defined $in){die "Usage:$0 filename";}my $out = $in;$out = ~s/(\.\w+)?$/.out/;if(! open $in_fh, '<',$in){die "Can't open '$in':$!";}if(! open $out_fh, '>',$in){die "Can't open '$out':$!";}while(<$in_fh>){s/Fred/Larry/gi;print $out_fh $_;}</span>

此程式一開始會先清點它的命令列參數,預期應該要一個。

 

3

<span style="font-size:18px;">my $in = $ARGV[0];if(! defined $in){die "Usage:$0 filename";}my $out = $in;$out = ~s/(\.\w+)?$/.out/;if(! open $in_fh, '<',$in){die "Can't open '$in':$!";}if(! open $out_fh, '>',$in){die "Can't open '$out':$!";}while(<$in_fh>){chomp;s/Fred/Larry/gi;s/Wilma/Fred/gi;s/\n/Wilma/g;print $out_fh “$_\n”;}</span>

我們必須先找到一個“預留位置”,而且必須是不會出現在資料中的。因為使用了chomp,所以我們知道分行符號(\n)是絕對不會出現在字串中的,所以分行符號就可以充當預留位置。


4

<span style="font-size:18px;">$^I = ".bak";while(<>){if(/\A#!/){$_.="##Copyright (C) 2015 by HSL\n";}print;}</span>


5.為避免重複加上著作權聲明,我們得分兩回處理所有檔案。第一回,我們會先建立一個雜湊,它的鍵是檔案名稱,而它的值是什麼並不重要。為了簡單起見,設為1。第二回,我們會把這個雜湊當成待辦事項清單逐個處理,並把已經包含著作權聲明行的檔案移除。目前正在讀取的檔案名稱可用$ARGV取得,所以可以直接把它拿來當雜湊鍵。

<span style="font-size:18px;">my %do_these;foreach(@ARGV){$do_these{$_} = 1;}while(<>){if(/\A## Copyright/){delete $do_these{$ARGV};}}@ARGV = sort keys %do_these;$_I = ".bak";while(<>){if(/\A#!/){$_ = "## Copyright (c) 2015 by HSL";}print;</span>


這一章節讓我更加深入地瞭解了如何用perl對檔案進行操作。與此同時,我正在繼續看我的VTR-to-Bitstream項目,其中在將Virtex-6改為ZYNQ遇到了不少的問題。不過正在和老師商討如何攻克。也開始著手看一些關於可重構計算的書了。

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

Perl Learning 8 Processing Text with Regular Expression

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.