Perl 特殊變量$/和$\
上集回顧
上次我們看了一下-M與-I這兩個(gè)搭檔
這次我們來(lái)看看這兩個(gè)特殊的”變量“$/和$\,不是參數(shù)。
解釋
$/ : 輸入記錄分隔符
$\ : 輸出記錄分隔符
說(shuō)實(shí)話,這兩個(gè)符號(hào)的確是有些詭異!可以這么來(lái)記,“太陽(yáng)出來(lái)我爬山坡,爬上山坡我好唱歌”,爬坡的是/(入),下坡的是\(出)。
這兩個(gè)變量是特殊變量,什么意思呢?就是它們是從娘胎里來(lái)的,本來(lái)就有,不需要你去聲明,它們就在那里。
為什么要說(shuō)這兩個(gè)變量呢?這兩個(gè)變量是什么意思呢?下面先說(shuō)明一下這兩個(gè)奇特的怪物究竟是個(gè)什么玩意。
比如在工廠車間的流水線,生產(chǎn)罐頭的那種。
[] [] [] [] [] [] [] [] [] [] [] []
->-->-->-->-->-->-->-->-->-->-->-->-->-->-->-->-->
| O O O O O O O O O O O O O O O O |
<--<--<--<--<--<--<--<--<--<--<--<--<--<--<--<--<-
當(dāng)?shù)玫匠善饭揞^之后,需要裝箱了,可是多少個(gè)裝一箱呢。
這個(gè)時(shí)候就有機(jī)器負(fù)責(zé)控制履帶移動(dòng)的長(zhǎng)度來(lái)控制幾個(gè)罐頭為一組進(jìn)行裝箱(罐頭之間間距相等)。
比如4個(gè)罐頭裝一箱,那好,當(dāng)過(guò)了一定長(zhǎng)度之后傳送帶停下來(lái),機(jī)械臂將4個(gè)罐頭裝箱,OK
|===================
-
| |
|
[] [] [] [] [] [] [] [] [] [] [] []
->-->-->-->-->-->-->-->-->-->-->-->-->-->-->-->-->
| O O O O O O O O O O O O O O O O |
<--<--<--<--<--<--<--<--<--<--<--<--<--<--<--<--<-
下一批
|===================
- ---------
| | | [] [] |
| | [] [] |
[] [] [] [] [] [] [] [] ---------
->-->-->-->-->-->-->-->-->-->-->-->-->-->-->-->--> ####################
| O O O O O O O O O O O O O O O O | ####################
<--<--<--<--<--<--<--<--<--<--<--<--<--<--<--<--<- ####################
再下一批
|===================
- --------- ---------
| | | [] [] | | [] [] |
| | [] [] | | [] [] |
[] [] [] [] --------- ---------
->-->-->-->-->-->-->-->-->-->-->-->-->-->-->-->--> ####################
| O O O O O O O O O O O O O O O O | ####################
<--<--<--<--<--<--<--<--<--<--<--<--<--<--<--<--<- ####################
假如我的包裝箱變大了,這次要裝6個(gè),怎么搞,好辦,設(shè)置一下傳送帶每次傳送的長(zhǎng)度就OK可
|=================== ---------
- | [] [] |
| | | [] [] |
| | [] [] |
[] [] [] [] [] [] ---------
->-->-->-->-->-->-->-->-->-->-->-->-->-->-->-->--> ####################
| O O O O O O O O O O O O O O O O | ####################
<--<--<--<--<--<--<--<--<--<--<--<--<--<--<--<--<- ####################
有的時(shí)候廠家搞活動(dòng),在箱子里面除了有罐頭,還有小禮品喲。
---------
| [] [] |--| +++
| [] [] | | +++ 小禮品,比如杯子,哈哈
| [] [] | +++
--------- +++
^^^^^^^^^^
||||||||||
上面是一個(gè)裝罐頭的箱子,外面用繩子系了個(gè)禮物在外面,我怕我靈魂畫手的功力太深,你們認(rèn)不出來(lái)~~
這里不妨把perl的文本處理流程當(dāng)作是工廠中的流水線,每次讀取一“行”,來(lái)處理。
-
$/就是說(shuō)在什么地方將文本分隔開(kāi)來(lái)作為一組”罐頭“,類似于控制傳送帶移動(dòng)的長(zhǎng)度。 -
$\就是當(dāng)我想打印文本的時(shí)候后面帶的小尾巴是什么,就像是上面的小禮品一樣。
現(xiàn)實(shí)世界與機(jī)器世界
平常我們讀書,從左到右轉(zhuǎn)頭就是一行。但是在機(jī)器世界,究竟什么是“行”,其實(shí)計(jì)算機(jī)的存儲(chǔ)是連續(xù)的,并不是說(shuō)想現(xiàn)實(shí)世界那樣還轉(zhuǎn)行之類的。那么究竟是如何區(qū)分行與行呢?
比如有一段序列
ATGCGTAGCTA
TAGCTAGCTTG
AA
其實(shí)真實(shí)的是這樣的
ATGCGTAGCTA\nTAGCTAGCTTG\nAA
當(dāng)然了,更加還原是以1和0表示,這里為了方便敘述。也就是說(shuō)在這三“行”序列之間是用一個(gè)\n連起來(lái)的,并不是像現(xiàn)實(shí)世界轉(zhuǎn)頭之類的。機(jī)器為了區(qū)分,每次讀到\n,就知道了到了一“行”了。
上面兩張圖說(shuō)明了現(xiàn)實(shí)的書本紙和機(jī)器世界的區(qū)別LF就是指\n。這個(gè)就是為了告訴機(jī)器要“換行了”。那么這里Perl不僅可以要機(jī)器在\n的地方換行,也可以自己設(shè)置如果碰到什么字符那就換行,比如!、~、@等等。
我之前有一個(gè)同學(xué)在處理文本的時(shí)候沒(méi)有將末尾的那個(gè)不可見(jiàn)的換行符去除,導(dǎo)致正則表達(dá)式無(wú)法匹配,也就無(wú)法得到正確結(jié)果,但是他換成從命令行輸出那一行信息卻可以匹配(從命令行讀取的不包含換行符)。一直糾結(jié),后來(lái)我給他說(shuō)了,他一直不相信,知道后來(lái)事實(shí)證明他沒(méi)搞清楚這個(gè)換行符。
額,可能被我搞的糊涂了,來(lái)看看例子就明白啦!
用法
$/ = "\n";
$\ = "\n";
這兩個(gè)就是變量,也就是說(shuō)可以直接對(duì)他們賦值
實(shí)例
- 示例1
# 這次不用-a與-F參數(shù)來(lái)處理
echo "12-34-56,45-23-67,678-56-12" | perl -n -e '
BEGIN{
# 在讀取數(shù)據(jù)之前就設(shè)置好輸入記錄分隔符
# 設(shè)置 , 作為“一行”的結(jié)尾的標(biāo)志
$/ = ",";
}
# 在將讀取的每一“行”的一系列用 - 連起來(lái)的數(shù)值進(jìn)行分隔
my @list = split /-/,$_;
# 對(duì)每組數(shù)值求和
my $total = 0; # 初始化變量
for my $num (@list){
$total += $num;
}
print "$total\n";
'
# 輸出
102
135
746
這里來(lái)解釋一下
| |
v v
12-34-56,45-23-67,678-56-12
箭頭所指的就是每次讀取的”一行“的停止位置,平常我們一般都是認(rèn)為換行符才是一行的末尾,但是這里$/大哥說(shuō)了,機(jī)器人的世界中的天上天下的——換行,都?xì)w我管 。也就是說(shuō)這里它重新定義了行的概念,就是說(shuō),按照,來(lái)作為標(biāo)志。比如
機(jī)器讀
12-34-56,
這是”一行“
再讀
45-23-67,
這是”一行“
在讀
678-56-12
這是”一行“
這里的“行”是指機(jī)器讀的行
來(lái)點(diǎn)實(shí)際的東西
- 示例2
假如有一個(gè)文件123.txt,內(nèi)容為
>atp1
AGTCAGCTGACTCGATCTACGTCTAGCGACGT
GATACGTACGTACGGTACTCGTAGCTACCGTA
TAGTAGC
>cox
ATGCGTAGCTATCGTAGCTAGCTCGATCGTCA
AGTAGCTCAGG
>nad1
ATGCTAGCTGACTTGACTGCATACGATGCTAG
GTAGTCATGCTAGCTAGC
其實(shí)在平常我們碰到很多fasta文件,它的序列是按照80個(gè)堿基為一行就進(jìn)行了換行了,所以我們后續(xù)處理有些麻煩。比如我們想要得到名為atp1的序列,那么就是當(dāng)我判斷了到了atp1之后,接下來(lái)就是序列,可是只打印出>atp1下面的一行卻不是它的完整序列,還需要繼續(xù)打印,直到碰到>cox,這樣其實(shí)某種程度上來(lái)說(shuō)就有點(diǎn)不太方便。
怎么做呢?你根據(jù)今天說(shuō)的內(nèi)容應(yīng)該想出來(lái)怎么辦了吧!
# 使用 > 作為輸入分隔符
# 代碼如下
cat 123.txt | perl -n -e '
BEGIN{
$/ = ">";
}
# 由于是以 > 作為分隔符,那么尾巴處就可能有>符號(hào)(除了最后一行可能沒(méi)有其他都有)
$_ =~ s/>$//;
# 正則表達(dá)式中\(zhòng)s*\r*使因?yàn)椴恢恢涝赼tp1后面是否有空格和回車符,所以加上
if($_ =~ m/^atp1\s*\r*\n/){
# 1. 也可以在這里除去里面的換行符
# print (substr($_,length($&)) =~ s/\r*\n//gr);
# 2. 也可以不去除
print ( substr($_,length($&) );
}
'
# 輸出為
AGTCAGCTGACTCGATCTACGTCTAGCGACGT
GATACGTACGTACGGTACTCGTAGCTACCGTA
TAGTAGC
這里我把分隔出來(lái)的每一批字符寫一下
- 第一批
>
- 第二批
atp1
AGTCAGCTGACTCGATCTACGTCTAGCGACGT
GATACGTACGTACGGTACTCGTAGCTACCGTA
TAGTAGC
>
- 第三批
cox
ATGCGTAGCTATCGTAGCTAGCTCGATCGTCA
AGTAGCTCAGG
>
- 第四批
nad1
ATGCTAGCTGACTTGACTGCATACGATGCTAG
GTAGTCATGCTAGCTAGC
注意:由于這里我們對(duì)機(jī)器世界的行進(jìn)行了重新定義,在這每一“行”中就可能存在多個(gè)\n,而“行”的結(jié)尾就變成了>。
$\
這個(gè)參數(shù)就是說(shuō)當(dāng)輸出的時(shí)候,在輸出的內(nèi)容后帶上一個(gè)小尾巴
比如
perl -e '
BEGIN{
$\ = "~";
}
for my $num (1..10){
print "$num";
}
'
# 輸出
1~2~3~4~5~6~7~8~9~10~
就是說(shuō)每次print,都會(huì)在print的內(nèi)容后面加上$\指定的內(nèi)容,這里是否想到減少按鍵盤的次數(shù)了。將$\賦值為\n。你自己多試一試哦。
后記
這一次并沒(méi)有說(shuō)參數(shù)相關(guān)的,而是說(shuō)了這兩個(gè)怪物,其實(shí)從第一篇再到這個(gè)第五篇,順序是按照我個(gè)人認(rèn)為的重要程度來(lái)述說(shuō)的,有點(diǎn)主觀?。〉且菍懙脑捑褪钦f(shuō)如果有一根線穿連著會(huì)不會(huì)更加有效一些。因?yàn)镻erl特別擅長(zhǎng)文本處理,而涉及到文本就不得不牽扯到換行啦,打印啦之類的。而這兩個(gè)特殊變量就是與之相關(guān)的,雖然怪異但是這兩個(gè)變量的確好用。對(duì)了,上面的例子都是搭配BEGIN{}和END{}搭配進(jìn)行的全局的分隔符的設(shè)置,其實(shí)有時(shí)候可以使用local $/ = ">",local $\ = "\n",之類的寫法來(lái)在局部塊中進(jìn)行設(shè)置。
相關(guān)
有關(guān)BEGIN{}和END{}的說(shuō)明已經(jīng)在之前的內(nèi)容中提到了??梢詤⒁?jiàn)
引用
版權(quán)聲明:本文采用 知識(shí)共享署名-非商業(yè)性使用-禁止演繹 4.0 國(guó)際許可協(xié)議 (CC BY-NC-ND 4.0) 進(jìn)行許可。