Perlの-0オプションは正確にどのように機能しますか?

Perlの-0オプションは正確にどのように機能しますか?

によるとman perlrun

-0[octal/hexadecimal]
     specifies the input record separator ($/) as an octal or
     hexadecimal number. If there are no digits, the null character is
     the separator. 

そして

The special value 00 will cause Perl to slurp files in paragraph
mode.  Any value 0400 or above will cause Perl to slurp files
whole, but by convention the value 0777 is the one normally used
for this purpose.

ただし、次の入力ファイルが与えられた場合:

This is paragraph one

This is paragraph two.

予期しない結果が出ました。

$ perl -0ne 'print; exit' file ## \0 is used, so everything is printed
This is paragraph one.

This is paragraph two.

 $ perl -00ne 'print; exit' file ## Paragraph mode, as expected
 This is paragraph one.

今まではそんなに良くなった。今、これらの2つが短絡モードでも機能しているように見えるのはなぜですか?

$ perl -000ne 'print; exit' file 
This is paragraph one.

$ perl -0000ne 'print; exit' file 
This is paragraph one.

なぜこれがファイル全体を再び食べたと思いますか?

$ perl -00000ne 'print; exit' file 
This is paragraph one.

This is paragraph two.

さらなるテストは、これらすべてが短絡モードで動作することを示した。

perl -000 
perl -0000
perl -000000
perl -0000000
perl -00000000

たとえこれらがファイル全体を食べるように見えますが:

perl -00000
perl -000000000

私の問題は、私が8進数を十分に理解していないことです(実際に)。私はプログラマーではなく、生物学者です。と?0000両方とも000000002つがファイル全体を食べますか>= 0400?それともまったく異なることが起こっていますか?

答え1

8進数は、10進数と同様に、0 == 0、0000 == 0、0 == 000000などです。実際、ここのスイッチは-0状況をやや混乱させる可能性があります。 「特殊値00」のポイントは、スイッチに対して1つのゼロを意味し、数値に0を追加しても変更されないことを意味すると仮定します。後者なので、同じ結果が得られます...

ある程度。などは000000少しエラーのように動作しますが、これは以下を参照する必要があることを覚えておいてください。単一の8ビット値。 8ビットの範囲は10進数で0~255、8進数で0~377です。したがって、ここでは3桁以上の数字を使用できません(特殊値はすべてその範囲外ですが、まだ3桁+スイッチ)。以下からこれを推論できます。

16進表記(-0xHHH ...)を使用して区切り文字を指定することもできます。ここで、Hは有効な16進数です。8進形式とは異なりこれは、すべてのUnicode文字を指定するために使用できます。0xFFを超える値でも

0xFF Hex == 255 Decimal == 377 Octal == (拡張) ASCII セットの 1 バイトおよび 1 文字サイズである最大 8 ビットです。

答え2

perl詳細については、ソースコードを見てみましょう。存在するperl.c:

case '0':
    {
     I32 flags = 0;
     STRLEN numlen;

     SvREFCNT_dec(PL_rs);
     if (s[1] == 'x' && s[2]) {
          const char *e = s+=2;
          U8 *tmps;

          while (*e)
        e++;
          numlen = e - s;
          flags = PERL_SCAN_SILENT_ILLDIGIT;
          rschar = (U32)grok_hex(s, &numlen, &flags, NULL);
          if (s + numlen < e) {
           rschar = 0; /* Grandfather -0xFOO as -0 -xFOO. */
           numlen = 0;
           s--;
          }
          PL_rs = newSVpvs("");
          SvGROW(PL_rs, (STRLEN)(UNISKIP(rschar) + 1));
          tmps = (U8*)SvPVX(PL_rs);
          uvchr_to_utf8(tmps, rschar);
          SvCUR_set(PL_rs, UNISKIP(rschar));
          SvUTF8_on(PL_rs);
     }
     else {
          numlen = 4;
          rschar = (U32)grok_oct(s, &numlen, &flags, NULL);
          if (rschar & ~((U8)~0))
           PL_rs = &PL_sv_undef;
          else if (!rschar && numlen >= 2)
           PL_rs = newSVpvs("");
          else {
           char ch = (char)rschar;
           PL_rs = newSVpvn(&ch, 1);
          }
     }
     sv_setsv(get_sv("/", GV_ADD), PL_rs);
     return s + numlen;
    }

グロンク_August8進数を表す文字列を数値形式に変換します。無効な8進数を入力しようとすると、すぐに返されます。すべての4文字(numlen = 4)が有効な値であると仮定します(実装ではforループを見ることができます)。数値.c)

したがって、-00000最初の項目は解析され、にperl設定されます。最後の項目が考慮され、リセットされます。以下で見ることができます:-0000$/\0000perl -0$/\000

$ perl -MO=Deparse -00000777ne 'print; exit' file
BEGIN { $/ = undef; $\ = undef; }
LINE: while (defined($_ = <ARGV>)) {
    print $_;
    exit;
}
-e syntax OK

$/undef最後に解析された8進数シーケンスがあっperlたので、銀に設定されました0777

より明確に言えば:

$ perl -MO=Deparse -00000x1FF -ne 'print; exit' file
BEGIN { $/ = "\x{1ff}"; $\ = undef; }
LINE: while (defined($_ = <ARGV>)) {
    print $_;
    exit;
}
-e syntax OK

$/最後の4桁の順序が設定されていることを確認できます0x1FF

関連情報