s替換
m//
模式用來匹配文本,也就是說用來找數據。而s///
用來查找並替換文本,所以可以用來處理文本文件。在有了正則的基礎之后,s///
用起來會簡單很多。
用法格式為:
$str =~ s/reg/replacement/FLAGS;
它表示用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修飾符,可以讓這個替換操作返回替換后的字符串。幾個注意點:
- r修飾符實際上是在替換前先拷貝一份待替換數據,然后在副本上進行替換,所以原始數據不會有任何改變
- r修飾符實際上是返回拷貝后的數據,如果替換成功,則返回替換后的字符串,如果替換失敗,則直接返回這個副本
- 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