Skip to Content

Perl

Perl 新遇到的錯誤訊息 : Experimental push on scalar is now forbidden

今天在執行 Perl 一段程式時,發現沒看過的錯誤訊息。

Experimental push on scalar is now forbidden ......

用 Google 查了一些資料,據說是 Perl 5.24 才有的。因為我之前換成 Win10,同時也把 Perl 更新至 5.24,想不到就遇上這個問題了。

錯誤的地方在這二行

push($self->{"tags"} , \%hash);
.....
my $hash = pop($self->{"tags"});
根據查到的例子,我改成如下就可以順利運作了。
push(@{$self->{"tags"}} , \%hash);
.....
my $hash = pop(@{$self->{"tags"}});

perl 在函數中宣告 my $_

以前在學 Perl 時,知道在函數中宣告變數可以用 local 或 my ,local 表示在它的宣告的區塊中,可以在該區塊調用的子函數中繼續使用。而 my 宣告的變數就不行了。
 
不過當時有一個特殊的限制,就是針對這個特殊的變數 $_,只能宣告為 local。不過在後來的新版本中,有看到可以宣告為 my,對此我也沒特別注意,今天寫程式時,就試用了一下,結果程式有不在預期中的結果,還 debug 半天,才發現就是 my $_ 造成的。剛剛寫了個小程式測試,才大概看出它的特性。
 
程式:
$_ = "123";
test1($_);
print "$_\n\n";     # $_ = 123
 
$_ = "123";
test2($_);
print "$_\n\n";     # $_ = 123
 
$_ = "123";
test3($_);
print "$_\n\n";     # $_ = abc , 在函數中被取代了
 
sub test1
{
    local $_ = shift;       # 使用 local
    s/123/abc/;             # 預設是處理 $_
    print "in  : $_\n";     # $_ = abc , 被取代了
    print "out : $::_\n";   # $::_ = abc , $::_ 暫時被取代了
}
 
sub test2
{
    my $_ = shift;          # 使用 my
    $_ =~ s/123/abc/;       # 取代的對像是內部的 $_
    print "in  : $_\n";     # $_ = abc , 被取代了
    print "out : $::_\n";   # $::_ = 123 , $::_ 完全沒有參與
}
 
sub test3
{
    my $_ = shift;          # 使用 my
    s/123/abc/;             # 【重點】預設取代的對像是 $::_ , 也就是 $main::_
    print "in  : $_\n";     # $_ = 123 , 區域變數完全沒有被取代
    print "out : $::_\n";   # $::_ = abc , 所以 $::_ 反而被取代了
}
 
結果如下:
in  : abc
out : abc
123
 
in  : abc
out : 123
123
 
in  : 123
out : abc
abc
 
總之,重點就是這二行要特別小心
my $_ = shift;
s/123/abc;
在副程式中宣告 my $_ 之後,就不能用 s/123/abc/; 這種方式來處理,因為它預設是處理全域變數的 $_,而不是副程式中宣告的 $_,若不注意,就會有非預期的結果。
 
如果要處理,就不可以偷懶,要寫清楚變數名稱
 
my $_ = shift;
$_ =~ s/123/abc;
這樣才是針對內部宣告的 $_ 來進行取代處理。
 

Perl Debug for VS Code

好一陣子以來,寫一些簡單的程式已改用 Visual Studio Code (以下簡稱 VS Code),跟以前用 UltraEdit 比起來,是方便蠻多的,算是一試成主顧。不過主要的優點還是在寫程式方面,至於一般的文字編輯,則改用 MadEdit ,最主要的原因是它有支援 Unicode Ext-B,至於 NotePad++ 和 UltraEdit (早期的版本) 則支援好像還不夠好。

另外,自從改用 Strawberry Perl 以來,因為沒有好用的除錯工具,覺得寫程式除錯很不方便,都是在程式中加一堆 Print 將結果印出來檢查。

前二天發現了一個 Perl Debug for VS Code ,簡單試了一下,只要指定好 Perl 的環境變數,就可以在 VS Code 中逐步執行 Perl 並中斷程式檢查結果了。

安裝也很簡單,就是在 VS Code 的環境下去搜尋擴充模組就可以找到了。

至於詳細使用,我也不太熟,我對 VS Code 本身的熟悉度還不夠,但光是寫程式時的流暢度,就令我驚艷到以它為主了。

本來也以為可以找到 Python 的 Debug 來試,但失敗了。可能是 Python 某個模組沒有支援到 Python 3.6 ,而我正是用 3.6 版的,也許過陣子再來試看看了。

[Perl] Perl Unicode全攻略(轉)

轉載本站文章請註明,轉載自:扶凱 [ http://www.php-oa.com ]
本文鏈接: http://www.php-oa.com/2008/12/13/perl-unicode.html
轉自:http://blog.chinaunix.net/u2/70049/showart_1210487.html

耐心看完本文, 相信你今後在unicode處理上不會再有什麼問題.

本文內容適用於perl 5.8及其以上版本.

以Perl 看來, 字符串只有兩種形式. 一種是octets, 即8位序列, 也就是我們通常說的字節數組二進製文件. 另一種utf8編碼的字符串, perl管它叫string. 也就是說: Perl只認識兩種編碼: Ascii(octets)和utf8(string).

utf8 flag

那麼perl如何確定一個字符串是octets 還是utf8編碼的字符串呢? perl可沒有什麼智能, 他完全是靠字符串上的utf8 flag. 在perl內部, 字符串結構由兩部分組成: 數據和utf8 flag (標記). 比如字符串"中國"在perl內部的存儲是這樣:

utf8 flag 數據
On On

如果utf8 flag 是On 的話, perl就會把中國當成utf8字符串來處理, 如果utf8 flag 為Off, perl 就會把他當成octets 來處理. 所有字符串相關的函數包括正則表達式都會受utf8 flag 的影響. 讓我們來看個例子:

程序代碼:

use  Encode;
use  strict;

my  $str  = "中國" ;
Encode::_utf8_on( $str );
print  length ( $str ) . "\n" ;
Encode::_utf8_off( $str );
print  length ( $str ) . "\n" ;

運行結果是:

程序代碼:
2
6

這裡我們使用Encode 模塊的_utf8_on 函數和_utf8_off 函數來開關字符串"中國"的utf8 flag. 可以看到, utf8 flag 打開的時候, "中國"被當成utf8字符串處理, 所以其長度是2. utf8 flag 關閉的時候, "中國"被當成octets(字節數組)處理, 出來的長度是6(我的編輯器用的是utf8 編碼, 如果你的編輯器用的是gb2312 編碼, 那麼長度應該是4) .

再來看看正則表達式的例子:

程序代碼:

use  Encode;
use  strict;

my  $a  = "china----中國" ;
my  $b  = "china----中國" ;
Encode::_utf8_on( $a );
Encode::_utf8_off( $b );
$a  =~ s/\W+//g;
$b  =~ s/\W+//g;
print  $a , "\n" ;
print  $b , "\n" ;

運行結果:

程序代碼:
Wide character in print at unicode.pl line 10.
china中國
china

結果第一行是一條警告, 這個我們稍後再討論. 結果的第二行說明, utf8 flag 開啟的情況下, 正則表達式中的\w能夠匹配中文, 反之則不能.

如何確定一個字符串的utf8 flag 是否已開啟? 使用Encode::is_utf8($str). 這個函數並不是用來檢測一個字符串是不是utf8 編碼, 而是僅僅看看它的utf8 flag 是否開啟.

perl 5.8 + GTK+

會去碰 GTK+,是昨天在試星際譯王 stardict 時,必須安裝 GTK+。過去知道 perl + GTK+ 可以做視窗介面的 perl 程式,但一直沒去研究這方面,因為大部份的工作都用命令列模式去處理了。

昨天即然裝了 GTK+,就想研究一下配合 perl 的效果,我相信同仁有時會比較希望使用視窗介面,結果試了半天,才知道它必須搭配 perl 5.8,這又觸動了另一個過去。

過去曾試著安裝 perl 5.8,結果發現許多過去寫的程式不能用,又沒太多時間一一研究,只好重新裝回 perl 5.6,雖然聽說 perl 5.8 有許多優點,對 unicode 的支援也很好,但就是沒空去玩,如今要試 GTK+ ,又遇到同樣的問題了。

我想由 perl 5.6 轉到 perl 5.8 不太簡單,畢竟過去在使用中的 perl 5.6 太多,也都很重要,要轉換到 perl 5.8 可能要做不少測試。不知能不能 perl 5.6 及 5.8 共同存在?若能共存,則在過渡期就比較安全了。

底下是一篇 autrijus 譯的 Perl 5.8.0 版釋出公告

用 Perl 讀取 MySQL

昨天 (3/23) 本來在整理經錄的資料庫,突然被提醒相關的程式動手寫了沒?

其實我先前都是用 Access 在整理資料庫,而實際寫過資料庫相關應用程式,都是用 C++ 或 C# 寫的,這次經錄要發表的是網路版的程式,原本是想到用 MySQL+PHP,但 PHP 沒玩過,結案的時間有點緊,想想還是用 Perl 比較安全。

Perl 雖然寫過一些程式,也處理過 CGI,但卻沒實際和 MySQL 搭配過,在資料庫方面只用過 Windows 系統上的 ODBC,因此昨天就想來試試 MySQL+Perl 的效果如何?尤其我擔心若 MySQL 支援的 unicode 不是 UTF8,就會有麻煩了,因為我只有 Perl 5.6 處理 UTF8 的經驗。

訂閱文章


about seo