1. 程式人生 > >Perl處理數據(一):s替換、split和Join

Perl處理數據(一):s替換、split和Join

即將 例如 strong subst 內容 返回結果 布爾邏輯 字串 搜索

m//模式用來匹配文本,也就是說用來找數據。而s///用來查找並替換文本,所以可以用來處理文本文件。在有了正則的基礎之後,s///用起來會簡單很多。

用法格式為:

$str =~ s/reg/replacement/;

它表示用reg去搜索$str中的內容,並將搜索出來的內容替換為replacement。

1.s///的斜線可以替換為其他對稱的符號(括號類)或相同的符號

例如s!!!s###s%%%s()()s{}{}s<><>s[][]等,還可以混用符號,例如s{}##s{}()等。

$str = "ma xiaofang or ma longshuai";

$str =~ s/ma/gao/g;

print "$str\n";

第二句直接會替換掉原來的$str

2.s//替換的返回值是替換成功的次數(數量)

例如上面使用全局替換修飾符g,使得替換了兩個"ma",返回值為2,如果去掉全局替換修飾符,則只替換第一個"ma",返回值為1。

所以,通過s///返回值可以當作布爾值來做判斷:沒有替換成功,將返回0,如果替換成功,則返回值至少為1。

$str ="ma xiaofang or ma longshuai";
print "substituted" if $str =~ s/ma/gao/;

3.還有一種操作符$str !~ s///,它的用法和=~是相同的,只不過它轉換了布爾邏輯:替換成功時返回false,替換失敗時返回1。

4.由於分組後會立即將分組捕獲的結果保存到特殊變量\1$1中,所以在replacement部分可以使用這些變量

$str = "gao xiaofang or ma longshuai";

$str =~ s/(gao)(.*)(ma)(.*)/\3$2\1$4/;   # \1和$1都可以在replacement中使用

print "$str\n";      # 輸出ma xiaofang or gao longshuai

修飾符

除了全局修飾符g外,m//可用的修飾符在s///中基本都可用,最常用的修飾符還是gimsx。此外,s///還有自己的修飾符r和e,稍後解釋。

$str = "Gao xiaofang or Ma longshuai";
$str =~ s/(gao).* or (ma).*/$2 xiaofang or $1 longshuai/ig;
print "$str\n";

再例如,壓縮空白:

s/(\s)+/\1/g;   # 將多個空白縮減成一個
s/^\s+//;       # 去除行首空白
s/\s+$//;       # 去除行尾空白
s/^\s+|\s+$//;  # 去除行首空白和行尾空白

r修飾符

原本s///的返回值是替換成功的次數,使用r修飾符,可以讓這個替換操作返回替換後的字符串。幾個註意點:

  1. r修飾符實際上是在替換前先拷貝一份待替換數據,然後在副本上進行替換,所以原始數據不會有任何改變
  2. r修飾符的替換返回結果一定是純文本字符串,即使它操作的是一個對象
$str = "ma xiaofang or ma longshuai";

print  $str =~ s/Ma/gao/igr,"\n";   # 輸出替換後的內容
print "$str\n";                     # 原始內容不變
$copy = $str =~ s/Ma/gao/igr,"\n";  # 替換後的內容賦值給新的變量
print "$copy\n";                    # 輸出替換後的內容

如果不使用r修飾符,想要將替換的內容輸出,只能先將其保存到一個新的變量中,然後輸出這個變量:

$str = "ma xiaofang or ma longshuai";

($copy = $str) =~ s/Ma/gao/ig;
print "$str\n";        # 原始數據不變
print "$copy\n";       # 替換後的數據

如果上面省略了括號,那麽表示$str被替換,且將成功替換的次數返回給$copy

#!/usr/bin/perl
$str = "ma xiaofang or ma longshuai";

$copy = $str =~ s/Ma/gao/ig;
print "$str\n";        # 輸出gao xiaofang or gao longshuai
print "$copy\n";       # 輸出2 

r修飾符在map函數中非常好用,它可以替換一個列表中的某些元素。

例如,下面的map將@list中首字母大寫的單詞替換為小寫。需要註意的是這裏使用了{}

@list = qw(Ma longshuai Gao xiaofang);
@new_list = map {s/([A-Z])([a-z]+)/\L\1\E\2/rg} @list;
print "@new_list\n";

e修飾符

e是一個超神的修飾符,它可以讓replacement部門當作一個後執行的表達式。

$str="ma longshuai or ma xiaofang";
$str =~ s/ma/$& x 2/eg;
print $str,"\n";

執行上面的程序,它將輸出"mama longshuai or mama xiaofang"

上面的過程大致為:搜索字符串"ma",然後將其保存到特殊變量$&中,在replacement部分,將其重復一次,所以得到"mama"。

甚至,可以用sprintf直接格式化輸出替換後的內容。

split函數

split函數用於將字符串分割為一個列表(所以在標量上下文返回的是列表的大小)。

split用法如下:

split /pattern_sep/,$string,limit

其中pattern_sep用於指定分隔符,允許使用正則表達式(一般都是很簡單的正則),且可以指定多個分隔符。limit表示最多分割為幾個元素,如果指定為1(默認),則表示盡可能多地分隔。,

例如,用split分割字符串abc:def::1234:xyz,分隔符指定為:

$str="abc:def::1234:xyz";
@list = split /:/,$str;
print "list: [@list]\n";
print "list_size: ",scalar(@list),"\n";

上面的字符串分割後將有5個元素:abc,def,空,1234,xyz。

可以加上一個limit參數,限制最多分隔為多少個元素,例如上面指定limit=2,表示只分隔一次:

$str="abc:def::1234:xyz";
@list = split /:/,$str,2;   # 返回"abc","def::1234:xyz"兩個元素

split在分割字符串的時候,如果分割後字符串首部會出現空字串,split會保留這些空元素,但如果是尾部空字串,則舍棄。

例如:

$str=":::abc:def:1234:xyz::::";
@new_list=join(".",split /:/,$str);
print "@new_list\n";       # 輸出:...abc.def.1234.xyz

上面使用了join函數,指定了用"."將split後列表中的各元素連接起來。

split可以指定多個分隔符,且可以使用正則表達式來表示。

例如:

$str="abc:def::12:xyz";
@list = split /::/,$str);  # 返回:"abc:def","12:xyz"
@list = split /[:]+/,$str);  # 返回:"abc","def","12","xyz"
@list = split /[:0-9]/,$str);  # 返回:"abc","def","","","","","xyz"

如果不設置分隔符,那麽將認為所有的空白(包括行首空白)都是分隔符,且會將連續的多個空白(即使是多個連續的空行)自動壓縮當作一個分隔符,但同時它必須也省略第二個字符串參數。也就是說,這時只能對$_進行處理。如果省略了分隔符,卻設置了待處理的字符串參數,則返回空。

$_="abc 123   xyz\tmn\t\tdef\n\nABC";
@arr=split;
print "@arr";   #輸出:abc 123 xyz mn def ABC

對省略分隔符做個總結:只要是空白,無論是否在行首,無論是否是換行符,所有連續空白都會被當作單個分隔符。

所以它有點類似於split /\s+/,$str的行為,只不過指定了分隔符的話就會保留行首一個空白。

還可以指定空分隔符,它會將字符串中的每個字符都分隔。

$str="abcdef";
print join(",",split //,$str);   # 輸出a,b,c,d,e,f

一般來說,分隔符的正則都很簡單,如果需要寫復雜的模式,請避免在分隔符正則中使用用於分組的括號,因為括號會被當作分隔符。如果想要使用括號,則可以使用非捕獲分組(?:)的形式。

join

join函數用於將列表中各個元素用給定字符連接起來,和split的行為有點相反。它返回一個列表。

join用法如下:

join $sep,$list

其中$sep只能是字符串,這一點和split不一樣。

例如:

print join "-",a,b,c,d,efg;   # 輸出:"a-b-c-d-efg"

可以將split後的結果用join換一個分隔符連接起來:

$str="abc:def::1234:xyz";
@new_list = join(",",split /:/,$str);
print "@new_list\n";          # 輸出:abc,def,,1234,xyz

Perl處理數據(一):s替換、split和Join