2016-05-13 44 views
2

如何解決以下問題?在perl中區分字符串和數字參數

use 5.014; 
use warnings; 
use Test::Simple tests => 4; 

ok(doit(0123) == 83, "arg as octal number"); 
ok(doit(83)  == 83, "arg as decimal number"); 
ok(doit('0123') == 83, "arg as string with leading zero"); 
ok(doit('123') == 83, "arg as string without leading zero"); 

sub doit { 
    my $x = shift; 
    return $x;          # how to replace this line 
    #return got_the_arg_as_string ? oct($x) : $x; # with something like this 
} 

例如,如果我傳遞doit子任何字符串 - 意味着引用值 - (帶或不帶前導零),它應該被轉換爲八進制值。否則,它只是一個數字。

+2

想知道行爲不同。對我來說,這看起來像是未來錯誤的來源... – jm666

+0

@cajwine:這與您在想要doit('123')的問題中所說的內容相矛盾嗎? – ysth

回答

6

Perl的標量的內部表示可能是整數或字符串,並且它隨時準備將該表示強制轉換爲任何其他標量類型。使用C/XS代碼可以獲得標量的內部類型。例如,JSON::XS模塊會執行此操作,以決定是將值呈現爲數字還是字符串。

這裏的理念,爲您的問題證明:

use Inline 'C'; 
sub foo { 
    my ($x) = @_; 
    print $x, " => isString: ", isString($x), "\n"; 
} 
foo(0123); 
foo('0123'); 

__END__ 
int isString(SV* sv) 
{ 
    return SvPOK(sv) ? 1 : 0; 
} 

程序輸出:

83 => isString: 0 
=> isString: 1 

相關文章:

Difference between $var = 500 and $var = '500'

When does the difference between a string and a number matter in Perl 5?

Why does the JSON module quote some numbers but not others?

更新一些這方面功能的核心B模塊中暴露出來,所以沒有必要添加爲XS依賴性:你爲什麼要這樣的接口,這裏的報價,不帶引號的參數

use B; 
sub isString { 
    my $scalar = shift; 
    return 0 != (B::svref_2object(\$scalar)->FLAGS & B::SVf_POK) 
} 
+2

'sub isNumber {no warnings「numeric」;長度($ _ [0]&「」)}' – ysth

+0

Ahh yes !!! '使用B'派生的'isString' *正是*爲我所尋找的。 @ysth的'isNumber'也可以工作,但'isString'的速度幾乎快了一倍。大!謝謝。 ;) – cajwine