2012-03-20 4 views
5

Я пишу вещь для вывода чего-то похожего на JSON, из структуры perl. Я хочу процитировать вести себя так:Есть ли способ проверить, был ли скаляр сканирован или нет?

"string" outputs "string" 
"05" outputs "05" 
"5" outputs "5" 
5 outputs 5 
05 outputs 5, or 05 would be acceptable 

JSON :: XS обрабатывает это путем тестирования, если скаляр был «строковой» или нет, я думаю, это очень здорово. Но я не могу найти способ сделать этот тест самостоятельно, не написав XS, которого я бы предпочел избежать. Это возможно? Я не могу найти это нигде в CPAN, не найдя обширного педантизма о Scalar :: Util :: looks_like_number и т. Д., Который полностью не то, что я хочу. Единственная остановка, которую я могу найти, это Devel :: Peek, которая чувствует зло. А также, как и JSON :: XS, я в порядке с этим secenario:

my $a = 5; 
print $a."\n"; 
# now $a outputs "5" instead of 5) 

ответ

5

Проверьте выход B::svref_2object:

use B; 
($x, $y, $z) = ("5", 5, 5.0); 

print ref(B::svref_2object(\$x)), "\n"; 
print ref(B::svref_2object(\$y)), "\n"; 
print ref(B::svref_2object(\$z)), "\n"; 

Выход:

B::PV 
B::IV 
B::NV 

Или, как Ikegami предлагает, если вы хотите, а выполните поиск pPOK флаг:

if (B::svref_2object(\$x)->FLAGS & B::SVp_POK) { 
    print "I guess \$x is stringy\n"; 
} 
+0

Это не имеет никакого отношения к типу SV. Это связано с флагом pPOK. – ikegami

+0

Например, посмотрите на 'my $ x =" "; $ Х = 5; my $ y = 5; "" $ У;. '. Оба являются PVIV, но только один является «волокнистым». – ikegami

+0

Я тоже это заметил. Было бы неплохо, если бы B фактически перечислил то, что он предоставил! К сожалению, похоже, что 'SvGETMAGIC' недоступен. – ikegami

2

Это, вероятно, не самый лучший способ, но если JSON делает то, что вы хотите, почему бы не использовать его?

sub is_stringy { 
    encode_json([$_[0]]) =~ /["']/ 
} 

is_stringy(5);  # undef 
is_string("5");  # 1 
+0

Скорее всего, я закончу, если не найду лучшего ответа. Тем не менее, это действительно расточительно. Я бы просто сохранил скалярный вывод JSON :: XS, но, к сожалению, то, что я выводил, не является JSON и имеет разные правила экранирования и т. Д. – Yobert

4

Вы можете сделать так, несколько больше не кажется, был строковой с помощью следующего:

$x = 0+$x; 

Например,

$ perl -MJSON::XS -E' 
    $_ = 4; 
    say encode_json([$_]); # [4] 
    "".$_; 
    say encode_json([$_]); # ["4"] 
    $_ = 0 + $_; 
    say encode_json([$_]); # [4] 
' 

Детектирование ли что-то было строковой жестче, потому что JSON :: XS изучает внутренности Perl. Можно использовать следующее:

sub is_stringy { 
    { no warnings 'void'; "".$_[0]; } 
    return 1; 
} 

, но я не думаю, что это то, что вы хотите :) Я не знаю, как обнаружить «коррупция», не написав некоторые XS код. То, что вы хотите знать, если SvPOKp верно для скаляра (после того, как вы назовёте SvGETMAGIC на скаляр).

use Inline C => <<'__EOI__'; 

    SV* is_stringy(SV* sv) { 
     SvGETMAGIC(sv); 
     return SvPOKp(sv) ? &PL_sv_yes : &PL_sv_no; 
    } 

__EOI__ 

$_ = 4; 
say is_stringy($_) ?1:0; # 0 
{ no warnings 'void'; "".$_; } 
say is_stringy($_) ?1:0; # 1 
$_ = 0+$_; 
say is_stringy($_) ?1:0; # 0 

oo! Оказывается, что B действительно обеспечивает SVp_POK, так что он может (почти) быть сделано без написания нового кода XS

use B qw(svref_2object SVp_POK); 

sub is_stringy { 
    my ($s) = @_; 
    my $sv = svref_2object(\$s); 
    #$sv->GETMAGIC(); # Not available 
    return $sv->FLAGS & SVp_POK; 
} 

Будучи не в состоянии назвать SvGETMAGIC имеет свои недостатки, но он будет работать почти все время.

+0

@Yobert, обновлено, снова. – ikegami