12

16 進から (未加工の) 2 進への変換に関するこの質問への回答として、「5 ~ 10 行の C またはその他の言語」で解決できるというコメントがありました。

(一部の) スクリプト言語で実現できると確信しており、その方法を知りたいと思っています。Cについても、そのコメントが正しいことを証明できますか?

注意: これは 16 進数からASCIIバイナリへの変換を意味するものではありません。具体的には、出力は入力 ASCII 16 進数に対応する生のオクテット ストリームである必要があります。また、入力パーサーは空白をスキップ/無視する必要があります。

edit (by Brian Campbell) 一貫性を保つために、次のルールを提案してもよろしいですか? これらが役に立たないと思われる場合は、自由に編集または削除してください。ただし、特定のケースがどのように機能するかについていくつかの議論があったため、いくつかの明確化が役立つと思います.

  1. プログラムは stdin から読み取り、stdout に書き込む必要があります (コマンドラインで渡されたファイルからの読み取りと書き込みを許可することもできますが、どの言語でも stdin と stdout よりも短いとは思えません)
  2. プログラムは、基本の標準言語ディストリビューションに含まれているパッケージのみを使用する必要があります。C/C++ の場合、これはそれぞれの標準ライブラリを意味し、POSIX ではありません。
  3. プログラムは、コンパイラまたはインタープリターに渡される特別なオプションなしでコンパイルまたは実行する必要があります (したがって、「gcc myprog.c」または「python myprog.py」または「ruby myprog.rb」は問題ありませんが、「ruby -rscanf myprog.rb」は問題ありません)。 ' は許可されていません; モジュールの要求/インポートは文字数にカウントされます)。
  4. プログラムは、オプションで空白で区切られた、隣接する 16 進数のペア (大文字、小文字、または大/小文字混合) で表される整数バイトを読み取り、対応するバイトを出力に書き込む必要があります。16 進数の各ペアは、最上位ニブルから順に書き込まれます。
  5. 無効な入力 ( 以外[a-fA-F \t\r\n]の文字、個々のバイト内の 2 つの文字を区切るスペース、入力の 16 進数の奇数) に対するプログラムの動作は未定義です。不正な入力に対する任意の動作 (ユーザーのコンピューターまたは何かに積極的に損害を与えることを除く) は許容されます (エラーをスローする、出力を停止する、不正な文字を無視する、1 文字を 1 バイトの値として扱う、すべて OK)
  6. プログラムは、追加のバイトを出力に書き込むことはできません。
  7. ソース ファイル内の合計バイト数が最も少ないコードがスコア付けされます。(または、元の課題により忠実にしたい場合、スコアはコードの行数が最も少ないことに基づいています。その場合、1 行あたり 80 文字の制限を課します。 1行のタイ)。
4

16 に答える 16

8

Edit Checkers は、私の C ソリューションを46 バイトに削減しました。これは、BillyONeal からのヒントとバグ修正のおかげで 44 バイトに削減されました (不正な入力に対する無限ループはなくなり、ループを終了するだけになりました)。これを 77 バイトから 46 バイトに削減した Checkers の功績を認めてください。

main(i){while(scanf("%2x",&i)>0)putchar(i);}

そして、私は前回よりもはるかに優れた Ruby ソリューションを持っています。42 38バイト (正規表現の提案をしてくれた Joshua Swank に感謝):

STDIN.read.scan(/\S\S/){|x|putc x.hex}

オリジナルのソリューション

C、77 バイト、または 2 行のコード (同じ行に配置できる場合は 1 になります#include)。これには、不正な入力の無限ループがあることに注意してください。Checkers と BillyONeal の助けを借りた 44 バイトのソリューションは、バグを修正し、単純に不正な入力で停止します。

#include <stdio.h>
int main(){char c;while(scanf("%2x",&c)!=EOF)putchar(c);}

通常どおりにフォーマットすると、わずか6行です。

#include <stdio.h>
int main() {
  char c;
  while (scanf("%2x",&c) != EOF)
    putchar(c);
}

Ruby、79 バイト (これは改善できると確信しています):

STDOUT.write STDIN.read.scan(/[^\s]\s*[^\s]\s*/).map{|x|x.to_i(16)}.pack("c*")

これらは両方とも STDIN から入力を受け取り、STDOUT に書き込みます

于 2009-04-27T21:57:28.577 に答える
7

45 バイトの実行可能ファイル (base64 エンコード):

6BQAitjoDwDA4AQI2LQCitDNIevrWMOy/7QGzSF09jLkBMAa5YDkByrEJA/D

(拡張子が .com のファイルに貼り付けます)

編集:わかりました、これがコードです。Windows のコンソールを開き、「hex.com」という名前の 45 バイトのファイルを作成し、「debug hex.com」と入力してから「a」と入力して入力します。次の行をコピーして貼り付けます。

db e8,14,00,8a,d8,e8,0f,00,c0,e0,04,08,d8,b4,02,8a,d0,cd,21,eb,eb,cd,20
db b2,ff,b4,06,cd,21,74,f6,32,e4,04,c0,1a,e5,80,e4,07,2a,c4,24,0f,c3

Enter、「w」を押してから、もう一度「q」を押して Enter を押します。「hex.com」を実行できるようになりました

EDIT2:2バイト小さくしました!

db e8, 11, 00, 8a, d8, e8, 0c, 00, b4, 02, 02, c0, 67, 8d, 14, c3
db cd, 21, eb, ec, ba, ff, 00, b4, 06, cd, 21, 74, 0c, 04, c0, 18
db ee, 80, e6, 07, 28, f0, 24, 0f, c3, cd, 20

それはトリッキーでした。そんなことに時間を費やしたなんて信じられない。

于 2009-04-28T15:10:56.313 に答える
7

39 文字の perl ワンライナー

y/A-Fa-f0-9//dc,print pack"H*",$_ for<>

編集:大文字を実際に受け入れていませんでした。修正されました。

于 2009-04-28T13:11:54.853 に答える
6

Brian の 77 バイトの C ソリューションは、関数プロトタイプに関する C の寛大さのおかげで、44 バイトに改善できます。

main(i){while(scanf("%2x",&i)>0)putchar(i);}
于 2009-04-28T01:47:21.613 に答える
4

Python の場合:

binary = binascii.unhexlify(hex_str)

ワンライン!(はい、これは詐欺です。)

于 2009-04-27T19:58:55.553 に答える
3

編集:このコードは、要件を具体化する質問の編集よりずっと前に書かれました。

C の 1 行に膨大な数のステートメントが含まれる可能性があることを考えると、役に立たないことはほぼ確実です。

C# では、10 行で実現可能ですが、ほぼ確実に 10 行以上で記述します。「文字列をバイト配列に変換する」部分から「ニブルを解析する」部分を分離します。

もちろん、間違った長さなどを気にしなければ、少しは楽になります。元のテキストにもスペースが含まれていました。それらはスキップしたり、検証したりする必要がありますか? それらは必要な入力形式の一部ですか?

私はむしろ、快適で読みやすい解決策がどのように見えるかを考慮せずにコメントが作成されたと疑っています.

そうは言っても、これは C# のひどいバージョンです。おまけに、1 ~ 2 行のコードを節約するために LINQ を完全に不適切に使用しています。もちろん、列はもっと長くなる可能性があります...

using System;
using System.Linq;

public class Test
{
    static void Main(string[] args)
    {
        byte[] data = ParseHex(args[0]);
        Console.WriteLine(BitConverter.ToString(data));

    }

    static byte[] ParseHex(string text)
    {
        Func<char, int> parseNybble = c => (c >= '0' && c <= '9') ? c-'0' : char.ToLower(c)-'a'+10;
        return Enumerable.Range(0, text.Length/2)
            .Select(x => (byte) ((parseNybble(text[x*2]) << 4) | parseNybble(text[x*2+1])))
            .ToArray();
    }
}

(これは、 などの組み込みの 16 進解析コードを使用することで「不正行為」を回避していConvert.ToByte(string, 16)ます。他のことは別として、それは単語 nybble の使用を失うことを意味します。これは常にボーナスです。)

于 2009-04-27T19:56:24.793 に答える
2

パール

もちろん、1 行 (かなり短い) で:

my $bin = map { chr hex } ($hex =~ /\G([0-9a-fA-F]{2})/g);
于 2009-04-27T22:52:34.263 に答える
2

ハスケル:

import Data.Char
import Numeric
import System.IO
import Foreign

main = hGetContents stdin >>= 
       return.fromHexStr.filter (not.isSpace) >>=  
       mapM_ (writeOneByte stdout)

fromHexStr (a:b:tl) = fromHexDgt [a,b]:fromHexStr tl
fromHexStr [] = []
fromHexDgt str =  case readHex str of 
  [(i,"")] -> fromIntegral (i)
  s -> error$show s

writeOneByte h i = allocaBytes 1 (wob' h i)
wob' :: Handle -> Int8 -> (Ptr Int8) -> IO ()
wob' h i ptr = poke ptr i >> hPutBuf h ptr 1
于 2009-04-28T00:44:54.617 に答える
2
.

「Hex!」と呼ばれる言語です。その唯一の使用法は、標準入力から 16 進データを読み取り、それを標準出力に出力することです。ヘックス!単純な python スクリプトによって解析されます。システムをインポート

try:
  data = open(sys.argv[1], 'r').read()
except IndexError:
  data = raw_input("hex!> ")
except Exception as e:
  print "Error occurred:",e

if data == ".":
  hex = raw_input()
  print int(hex, 16)
else:
  print "parsing error"
于 2010-05-18T13:16:46.147 に答える
1

かなり読みやすいCソリューション(9つの「実際の」行):

#include <stdio.h>
int getNextHexDigit() {
    int v;
    while((v = fgetc(stdin)) < '0' && v != -1) {    /* Until non-whitespace or EOF */
    }
    return v > '9' ? 9 + (v & 0x0F) : v - '0';      /* Extract number from hex digit (ASCII) */
}
int main() {
    int v;
    fputc(v = (getNextHexDigit() << 4) | getNextHexDigit(), stdout);
    return v > 0 ? main(0) : 0;
}

16 ビットのリトル エンディアンをサポートするには、次のものに置き換えmainます。

int main() {
    int v, q;
    v = (getNextHexDigit() << 4) | getNextHexDigit();
    fputc(q = (getNextHexDigit() << 4) | getNextHexDigit(), stdout);
    fputc(v, stdout);
    return (v | q) > 0 ? main(0) : 0;
}
于 2009-04-27T20:24:40.513 に答える
1

31 文字の Perl ソリューション:

s/\W//g,print(pack'H*',$_)for<>

于 2009-05-20T23:49:49.853 に答える
0

ゲームには遅れていますが、ここにいくつかの Python{2,3} ワンライナー (100 文字、必要import sys, re) があります:

sys.stdout.write(''.join([chr(int(x,16)) for x in re.findall(r'[A-Fa-f0-9]{2}', sys.stdin.read())]))
于 2011-09-25T12:41:21.597 に答える
0

これを頭の中でコーディングすることはできませんが、2 文字ごとに (byte)((AsciiValueChar1-(AsciiValueChar1>64?48:55)*16)+(AsciiValueChar1-(AsciiValueChar1>64?48: 55))) 16 進文字列を生のバイナリに変更します。入力文字列に 0 から 9 または A から B 以外の文字列が含まれていると、これはひどく壊れてしまうため、これがどれほど役立つかはわかりません。

于 2009-04-27T20:02:53.140 に答える