代码高尔夫 - 十六进制到(原始)二进制转换

发布于 2024-07-18 22:15:46 字数 1173 浏览 10 评论 0原文

为了回应这个问题询问十六进制到(原始)二进制转换,评论建议它可以用“5-10 行 C 语言或任何其他语言”来解决。

我确信对于(某些)脚本语言来说这是可以实现的,并且想看看如何实现。 我们能证明这个评论对于 C 来说也是正确的吗?

注意:这并不意味着十六进制到 ASCII 二进制 - 具体来说,输出应该是与输入 ASCII 十六进制相对应的原始八位字节流。 此外,输入解析器应该跳过/忽略空格。

编辑(作者:Brian Campbell)为了保持一致性,我可以提出以下规则吗? 如果您认为这些内容没有帮助,请随意编辑或删除它们,但我认为由于已经对某些情况应如何工作进行了一些讨论,因此进行一些澄清会有所帮助。

  1. 程序必须从标准输入读取并写入标准输出(我们也可以允许读取和写入命令行上传入的文件,但我无法想象在任何语言中这都会比标准输入和标准输出更短)
  2. 程序必须使用仅包含在您的基本标准语言发行版中的软件包。 对于 C/C++,这意味着它们各自的标准库,而不是 POSIX。
  3. 该程序必须在没有任何特殊选项传递给编译器或解释器的情况下编译或运行(因此,“gcc myprog.c”或“python myprog.py”或“ruby myprog.rb”都可以,而“ruby -rscanf myprog.rb”) ' 是不允许的;要求/导入模块会计入您的字符数)。
  4. 程序应读取由相邻的十六进制数字对(大写、小写或混合大小写)表示的整数字节,可以选择用空格分隔,并将相应的字节写入输出。 每对十六进制数字首先写入最高有效的半字节。
  5. 程序在无效输入时的行为(除 [a-fA-F \t\r\n] 之外的字符、分隔单个字节中两个字符的空格、奇数个十六进制数字)输入)未定义; 对错误输入的任何行为(除了主动损坏用户的计算机或其他东西)都是可以接受的(抛出错误、停止输出、忽略错误字符、将单个字符视为一个字节的值,都可以)
  6. 。要输出的附加字节。
  7. 代码按源文件中最少的总字节数进行评分。 (或者,如果我们想要更真实地对待最初的挑战,分数将基于最低的代码行数;在这种情况下,我会每行施加 80 个字符的限制,否则你会得到一堆1 条线的联系)。

In response to this question asking about hex to (raw) binary conversion, a comment suggested that it could be solved in "5-10 lines of C, or any other language."

I'm sure that for (some) scripting languages that could be achieved, and would like to see how. Can we prove that comment true, for C, too?

NB: this doesn't mean hex to ASCII binary - specifically the output should be a raw octet stream corresponding to the input ASCII hex. Also, the input parser should skip/ignore white space.

edit (by Brian Campbell) May I propose the following rules, for consistency? Feel free to edit or delete these if you don't think these are helpful, but I think that since there has been some discussion of how certain cases should work, some clarification would be helpful.

  1. The program must read from stdin and write to stdout (we could also allow reading from and writing to files passed in on the command line, but I can't imagine that would be shorter in any language than stdin and stdout)
  2. The program must use only packages included with your base, standard language distribution. In the case of C/C++, this means their respective standard libraries, and not POSIX.
  3. The program must compile or run without any special options passed to the compiler or interpreter (so, 'gcc myprog.c' or 'python myprog.py' or 'ruby myprog.rb' are OK, while 'ruby -rscanf myprog.rb' is not allowed; requiring/importing modules counts against your character count).
  4. The program should read integer bytes represented by pairs of adjacent hexadecimal digits (upper, lower, or mixed case), optionally separated by whitespace, and write the corresponding bytes to output. Each pair of hexadecimal digits is written with most significant nibble first.
  5. The behavior of the program on invalid input (characters besides [a-fA-F \t\r\n], spaces separating the two characters in an individual byte, an odd number of hex digits in the input) is undefined; any behavior (other than actively damaging the user's computer or something) on bad input is acceptable (throwing an error, stopping output, ignoring bad characters, treating a single character as the value of one byte, are all OK)
  6. The program may write no additional bytes to output.
  7. Code is scored by fewest total bytes in the source file. (Or, if we wanted to be more true to the original challenge, the score would be based on lowest number of lines of code; I would impose an 80 character limit per line in that case, since otherwise you'd get a bunch of ties for 1 line).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

江城子 2024-07-25 22:15:46

编辑 Checkers 将我的 C 解决方案简化为 46 字节,然后由于 BillyONeal 的提示以及我的错误修复而减少到 44 字节(不再有错误输入的无限循环,现在它只是终止循环)。 请感谢 Checkers 将其从 77 字节减少到 46 字节:

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 个字节或两行代码(如果您可以将 #include 放在同一行,则为 1)。 请注意,这会在错误输入时出现无限循环; 在 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 bytes (我相信这可以改进):

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

这些都从 STDIN 获取输入并写入 STDOUT

edit Checkers has reduced my C solution to 46 bytes, which was then reduced to 44 bytes thanks to a tip from BillyONeal plus a bugfix on my part (no more infinite loop on bad input, now it just terminates the loop). Please give credit to Checkers for reducing this from 77 to 46 bytes:

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

And I have a much better Ruby solution than my last, in 42 38 bytes (thanks to Joshua Swank for the regexp suggestion):

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

original solutions

C, in 77 bytes, or two lines of code (would be 1 if you could put the #include on the same line). Note that this has an infinite loop on bad input; the 44 byte solution with the help of Checkers and BillyONeal fixes the bug, and simply stops on bad input.

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

It's even just 6 lines if you format it normally:

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

Ruby, 79 bytes (I'm sure this can be improved):

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

These both take input from STDIN and write to STDOUT

自此以后,行同陌路 2024-07-25 22:15:46

39 char perl oneliner

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

编辑: 并没有真正接受大写,已修复。

39 char perl oneliner

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

Edit: wasn't really accepting uppercase, fixed.

醉态萌生 2024-07-25 22:15:46

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”并输入。 您现在可以运行“hex.com”

EDIT2:使其小两个字节!

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

这很棘手。 我不敢相信我花了时间这么做。

45 byte executable (base64 encoded):

6BQAitjoDwDA4AQI2LQCitDNIevrWMOy/7QGzSF09jLkBMAa5YDkByrEJA/D

(paste into a file with a .com extension)

EDIT: Ok, here's the code. Open a Window's console, create a file with 45 bytes called 'hex.com', type "debug hex.com" then 'a' and enter. Copy and paste these lines:

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

Press enter, 'w' and then enter again, 'q' and enter. You can now run 'hex.com'

EDIT2: Made it two bytes smaller!

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

That was tricky. I can't believe I spent time doing that.

灯下孤影 2024-07-25 22:15:46

Brian 的 77 字节 C 解决方案可以改进为44 个字节,这要归功于 C 对函数原型的宽松。

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

Brian's 77-byte C solution can be improved to 44 bytes, thanks to leniency of C with regard to function prototypes.

main(i){while(scanf("%2x",&i)>0)putchar(i);}
逆夏时光 2024-07-25 22:15:46

在 Python 中:

binary = binascii.unhexlify(hex_str)

一行! (是的,这是作弊。)

In Python:

binary = binascii.unhexlify(hex_str)

ONE LINE! (Yes, this is cheating.)

百善笑为先 2024-07-25 22:15:46

编辑: 这段代码是在问题编辑之前很长时间编写的,它充实了需求。

鉴于单行 C 可以包含大量语句,它几乎肯定是正确的,但没有用处。

在 C# 中,我几乎肯定会用超过 10 行来编写它,尽管在 10 行内可行。我将“解析 nybble”部分与“将字符串转换为字符串”部分分开。字节数组”部分。

当然,如果你不关心发现不正确的长度等,它就会变得容易一些。 您的原始文本也包含空格 - 是否应该跳过、验证这些空格等? 它们是必需输入格式的一部分吗?

我相当怀疑这个评论是在没有考虑到一个令人愉快、可读的解决方案是什么样子的。

话虽如此,这里有一个可怕的 C# 版本。 为了获得奖励,它完全不恰当地使用了 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();
    }
}

(这是通过使用任何内置的十六进制解析代码来避免“作弊”,例如 Convert.ToByte(string, 16)。除了其他任何事情之外,这意味着失去 nybble 这个词的使用,这总是一个好处。)

EDIT: This code was written a long time before the question edit which fleshed out the requirements.

Given that a single line of C can contain a huge number of statements, it's almost certainly true without being useful.

In C# I'd almost certainly write it in more than 10 lines, even though it would be feasible in 10. I'd separate out the "parse nybble" part from the "convert a string to a byte array" part.

Of course, if you don't care about spotting incorrect lengths etc, it becomes a bit easier. Your original text also contained spaces - should those be skipped, validated, etc? Are they part of the required input format?

I rather suspect that the comment was made without consideration as to what a pleasant, readable solution would look like.

Having said that, here's a hideous version in C#. For bonus points, it uses LINQ completely inappropriately in an effort to save a line or two of code. The lines could be longer, of course...

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();
    }
}

(This is avoiding "cheating" by using any built-in hex parsing code, such as Convert.ToByte(string, 16). Aside from anything else, that would mean losing the use of the word nybble, which is always a bonus.)

夜巴黎 2024-07-25 22:15:46

Perl中只有一行(相当短):

当然,

my $bin = map { chr hex } ($hex =~ /\G([0-9a-fA-F]{2})/g);

Perl

In, of course, one (fairly short) line:

my $bin = map { chr hex } ($hex =~ /\G([0-9a-fA-F]{2})/g);
梦在深巷 2024-07-25 22:15:46

哈斯克尔:

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

Haskell:

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
清浅ˋ旧时光 2024-07-25 22:15:46

嘎。

你不可以打电话给我询问我的即兴估算! ;-P

这是一个 9 行 C 版本,没有奇怪的格式(好吧,我同意你将 tohex 数组更好地分成 16 行,这样你就可以看到哪些字符代码映射到哪些值......),并且仅除了一次性脚本之外,我不会在任何其他脚本中部署两个快捷方式:

#include <stdio.h>
char hextonum[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
char input[81]="8b1f0008023149f60300f1f375f40c72f77508507676720c560d75f002e5ce000861130200000000";
void main(void){
   int i = 0;
   FILE *fd = fopen("outfile.bin", "wb");
   while((input[i] != 0) && (input[i+1] != 0))
      fputc(hextonum[input[i++]] * 16 + hextonum[input[i++]], fd);
}

没有组合行(每个语句都有自己的行),它完全可读,等等。混淆版本无疑可以更短,人们可以欺骗并把右大括号与前面的语句在同一行,等等,等等。

我不喜欢的两件事是我在那里没有 close(fd) ,并且 main 不应该是 void并且应该返回一个 int 。 可以说它们是不需要的 - 操作系统将释放程序使用的所有资源,文件将毫无问题地关闭,并且编译器将处理程序退出值。 鉴于它是一次性使用脚本,这是可以接受的,但不要部署它。

两者都变成了十一行,所以无论如何它都不是一个巨大的增加,十行版本将包括一个或另一个,这取决于人们可能觉得哪一个是两害相权取其轻。

它不进行任何错误检查,并且不允许空格 - 再次假设它是一次性程序,那么在运行脚本之前进行搜索/替换并删除空格和其他空格会更快,但是它应该不需要多于另外几行来吃掉空格。

当然,有一些方法可以使其更短,但它们可能会显着降低可读性……

哼。 只需阅读有关行长度的评论,所以这是一个较新的版本,带有更丑陋的十六进制宏,而不是数组:

#include <stdio.h>
#define hextonum(x) (((x)<'A')?((x)-'0'):(((x)<'a')?((x)+10-'A'):((x)+10-'a')))
char input[81]="8b1f0008023149f60300f1f375f40c72f77508507676720c560d75f002e5ce000861130200000000";
void main(void){
   int i = 0;
   FILE *fd = fopen("outfile.bin", "wb");
   for(i=0;(input[i] != 0) && (input[i+1] != 0);i+=2)
      fputc(hextonum(input[i]) * 16 + hextonum(input[i+1]), fd);
}

它并不是完全不可读,但我知道很多人对三元运算符有疑问,但是宏的适当命名和一些分析应该很容易让普通 C 程序员了解它是如何工作的。 由于宏中的副作用,我不得不转移到 for 循环,因此我不必为 i+=2 编写另一行(hextonum(i++) 每次调用时都会将 i 增加 5 ,宏观副作用不适合胆小的人!)。

此外,输入解析器应该跳过/忽略空格。

抱怨,抱怨,抱怨。

我必须添加几行来满足此要求,现在合理格式化的版本最多可添加 14 行。 它将忽略所有不是十六进制字符的内容:

#include <stdio.h>
int hextonum[] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
char input[]="8b1f 0008 0231 49f6 0300 f1f3 75f4 0c72 f775 0850 7676 720c 560d 75f0 02e5 ce00 0861 1302 0000 0000";
void main(void){
   unsigned char i = 0, nibble = 1, byte = 0;
   FILE *fd = fopen("outfile.bin", "wb");
   for(i=0;input[i] != 0;i++){
      if(hextonum[input[i]] == -1)
         continue;
      byte = (byte << 4) + hextonum[input[i]];
      if((nibble ^= 0x01) == 0x01)
         fputc(byte, fd);
   }
}

我没有考虑 80 个字符的行长度,因为输入甚至不少于 80 个字符,但 3 级三元宏可以替换第一个 256 个条目数组。 如果不介意一点“替代格式”,那么下面的 10 行版本并不是完全无法阅读:

#include <stdio.h>
int hextonum[] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
char input[]="8b1f 0008 0231 49f6 0300 f1f3 75f4 0c72 f775 0850 7676 720c 560d 75f0 02e5 ce00 0861 1302 0000 0000";
void main(void){
   unsigned char i = 0, nibble = 1, byte = 0;
   FILE *fd = fopen("outfile.bin", "wb");
   for(i=0;input[i] != 0;i++){
      if(hextonum[input[i]] == -1) continue;
      byte = (byte << 4) + hextonum[input[i]];
      if((nibble ^= 0x01) == 0x01) fputc(byte, fd);}}

而且,进一步的混淆和位调整可能会导致一个更短的示例。

Gah.

You aren't allowed to call me on my off-the-cuff estimates! ;-P

Here's a 9 line C version with no odd formatting (Well, I'll grant you that the tohex array would be better split into 16 lines so you can see which character codes map to which values...), and only 2 shortcuts that I wouldn't deploy in anything other than a one-off script:

#include <stdio.h>
char hextonum[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
char input[81]="8b1f0008023149f60300f1f375f40c72f77508507676720c560d75f002e5ce000861130200000000";
void main(void){
   int i = 0;
   FILE *fd = fopen("outfile.bin", "wb");
   while((input[i] != 0) && (input[i+1] != 0))
      fputc(hextonum[input[i++]] * 16 + hextonum[input[i++]], fd);
}

No combined lines (each statement is given its own line), it's perfectly readable, etc. An obfuscated version could undoubtedly be shorter, one could cheat and put the close braces on the same line as the preceding statement, etc, etc, etc.

The two things I don't like about it is that I don't have a close(fd) in there, and main shouldn't be void and should return an int. Arguably they're not needed - the OS will release every resource the program used, the file will close without any problems, and the compiler will take care of the program exit value. Given that it's a one-time use script, it's acceptable, but don't deploy this.

It becomes eleven lines with both, so it's not a huge increase anyway, and a ten line version would include one or the other depending on which one might feel is the lessor of two evils.

It doesn't do any error checking, and it doesn't allow whitespace - assuming, again, that it's a one time program then it's faster to do search/replace and get rid of spaces and other whitespace before running the script, however it shouldn't need more than another few lines to eat whitespace as well.

There are, of course, ways to make it shorter but they would likely decrease readability significantly...

Hmph. Just read the comment about line length, so here's a newer version with an uglier hextonum macro, rather than the array:

#include <stdio.h>
#define hextonum(x) (((x)<'A')?((x)-'0'):(((x)<'a')?((x)+10-'A'):((x)+10-'a')))
char input[81]="8b1f0008023149f60300f1f375f40c72f77508507676720c560d75f002e5ce000861130200000000";
void main(void){
   int i = 0;
   FILE *fd = fopen("outfile.bin", "wb");
   for(i=0;(input[i] != 0) && (input[i+1] != 0);i+=2)
      fputc(hextonum(input[i]) * 16 + hextonum(input[i+1]), fd);
}

It isn't horribly unreadable, but I know many people have issues with the ternary operator, but the appropriate naming of the macro and some analysis should readily yield how it works to the average C programmer. Due to side effects in the macro I had to move to a for loop so I didn't have to have another line for i+=2 (hextonum(i++) will increment i by 5 each time it's called, macro side effects are not for the faint of heart!).

Also, the input parser should skip/ignore white space.

grumble, grumble, grumble.

I had to add a few lines to take care of this requirement, now up to 14 lines for a reasonably formatted version. It will ignore everything that's not a hexadecimal character:

#include <stdio.h>
int hextonum[] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
char input[]="8b1f 0008 0231 49f6 0300 f1f3 75f4 0c72 f775 0850 7676 720c 560d 75f0 02e5 ce00 0861 1302 0000 0000";
void main(void){
   unsigned char i = 0, nibble = 1, byte = 0;
   FILE *fd = fopen("outfile.bin", "wb");
   for(i=0;input[i] != 0;i++){
      if(hextonum[input[i]] == -1)
         continue;
      byte = (byte << 4) + hextonum[input[i]];
      if((nibble ^= 0x01) == 0x01)
         fputc(byte, fd);
   }
}

I didn't bother with the 80 character line length because the input isn't even less than 80 characters, but a 3 level ternary macro could replace the first 256 entry array. If one didn't mind a bit of "alternative formatting" then the following 10 line version isn't completely unreadable:

#include <stdio.h>
int hextonum[] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
char input[]="8b1f 0008 0231 49f6 0300 f1f3 75f4 0c72 f775 0850 7676 720c 560d 75f0 02e5 ce00 0861 1302 0000 0000";
void main(void){
   unsigned char i = 0, nibble = 1, byte = 0;
   FILE *fd = fopen("outfile.bin", "wb");
   for(i=0;input[i] != 0;i++){
      if(hextonum[input[i]] == -1) continue;
      byte = (byte << 4) + hextonum[input[i]];
      if((nibble ^= 0x01) == 0x01) fputc(byte, fd);}}

And, again, further obfuscation and bit twiddling could result in an even shorter example.

萌︼了一个春 2024-07-25 22:15:46
.

它是一种称为“十六进制!”的语言。 它的唯一用途是从 stdin 读取十六进制数据并将其输出到 stdout。
十六进制! 由一个简单的 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"
.

Its an language called "Hex!". Its only usage is to read hex data from stdin and output it to stdout.
Hex! is parsed by an simple python script.
import sys

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"
绝對不後悔。 2024-07-25 22:15:46

相当易读的 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;
}

Fairly readably C solution (9 "real" lines):

#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;
}

To support 16-bit little endian goodness, replace main with:

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;
}
辞旧 2024-07-25 22:15:46

31 个字符的 Perl 解决方案:


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

A 31-character Perl solution:


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

笑叹一世浮沉 2024-07-25 22:15:46

我无法直接编码,但对于每两个字符,输出 (byte)((AsciiValueChar1-(AsciiValueChar1>64?48:55)*16)+(AsciiValueChar1-(AsciiValueChar1>64?48: 55)))将十六进制字符串更改为原始二进制文件。 如果您的输入字符串包含 0 到 9 或 A 到 B 以外的任何内容,这会严重破坏,所以我不能说它对您有多大用处。

I can't code this off the top of my head, but for every two characters, output (byte)((AsciiValueChar1-(AsciiValueChar1>64?48:55)*16)+(AsciiValueChar1-(AsciiValueChar1>64?48:55))) to get a hex string changed into raw binary. This would break horribly if your input string has anything other than 0 to 9 or A to B, so I can't say how useful it would be to you.

嘿看小鸭子会跑 2024-07-25 22:15:46

我知道 Jon 已经发布了一个(更干净的)LINQ 解决方案。 但这一次我能够使用 LINQ 语句,该语句在执行期间修改字符串并滥用 LINQ 的延迟评估,而不会受到同事的斥责。 :p

string hex = "FFA042";
byte[] bytes =
    hex.ToCharArray()
       .Select(c => ('0' <= c && c <= '9') ? 
                         c - '0' :
                         10 + (('a' <= c) ? c - 'a' : c - 'A'))
       .Select(c => (hex = hex.Remove(0, 1)).Length > 0 ? (new int[] {
           c,
           hex.ToCharArray()
                 .Select(c2 => ('0' <= c2 && c2 <= '9') ?
                                    c2 - '0' :
                                    10 + (('a' <= c2) ? c2 - 'a' : c2 - 'A'))
                 .FirstOrDefault() }) : ( new int[] { c } ) )
       .Where(c => (hex.Length % 2) == 1)
       .Select(ca => ((byte)((ca[0] << 4) + ca[1]))).ToArray();

1 条语句经过格式化以提高可读性。

更新

支持空格和不均匀的小数位数(89A 等于 08 9A)

byte[] bytes =
    hex.ToCharArray()
       .Where(c => c != ' ')
       .Reverse()
       .Select(c => (char)(c2 | 32) % 39 - 9)
       .Select(c => 
           (hex =
                new string('0', 
                           (2 + (hex.Replace(" ", "").Length % 2)) *
                                hex.Replace(" ", "")[0].CompareTo('0')
                                                       .CompareTo(0)) +
                hex.Replace(" ", "").Remove(hex.Replace(" ", "").Length - 1))
              .Length > 0 ? (new int[] {
                        hex.ToCharArray()
                           .Reverse()
                           .Select(c2 => (char)(c2 | 32) % 39 - 9)
                           .FirstOrDefault(), c }) : new int[] { 0, c } )
                     .Where(c => (hex.Length % 2) == 1)
                     .Select(ca => ((byte)((ca[0] << 4) + ca[1])))
                     .Reverse().ToArray();

还是一种说法。 通过在开头运行十六进制字符串的replace(" ", "") 可以使代码变得更短,但这将是第二条语句。

这一点有两个有趣的点。 如何在不借助源字符串本身以外的外部变量的情况下跟踪字符计数。 在解决这个问题时,我遇到了这样一个事实: char y.CompareTo(x) 仅返回“y - x”,而 int y.CompareTo(x) 返回 -1、0 或 1。所以 char y.CompareTo(x).CompareTo(0 ) 等于返回 -1、0 或 1 的 char 比较。

I know Jon posted a (cleaner) LINQ solution already. But for once I am able to use a LINQ statement which modifies a string during its execution and abuses LINQ's deferred evaluation without getting yelled at by my co-workers. :p

string hex = "FFA042";
byte[] bytes =
    hex.ToCharArray()
       .Select(c => ('0' <= c && c <= '9') ? 
                         c - '0' :
                         10 + (('a' <= c) ? c - 'a' : c - 'A'))
       .Select(c => (hex = hex.Remove(0, 1)).Length > 0 ? (new int[] {
           c,
           hex.ToCharArray()
                 .Select(c2 => ('0' <= c2 && c2 <= '9') ?
                                    c2 - '0' :
                                    10 + (('a' <= c2) ? c2 - 'a' : c2 - 'A'))
                 .FirstOrDefault() }) : ( new int[] { c } ) )
       .Where(c => (hex.Length % 2) == 1)
       .Select(ca => ((byte)((ca[0] << 4) + ca[1]))).ToArray();

1 statement formatted for readability.

Update

Support for spaces and uneven amount of decimals (89A is equal to 08 9A)

byte[] bytes =
    hex.ToCharArray()
       .Where(c => c != ' ')
       .Reverse()
       .Select(c => (char)(c2 | 32) % 39 - 9)
       .Select(c => 
           (hex =
                new string('0', 
                           (2 + (hex.Replace(" ", "").Length % 2)) *
                                hex.Replace(" ", "")[0].CompareTo('0')
                                                       .CompareTo(0)) +
                hex.Replace(" ", "").Remove(hex.Replace(" ", "").Length - 1))
              .Length > 0 ? (new int[] {
                        hex.ToCharArray()
                           .Reverse()
                           .Select(c2 => (char)(c2 | 32) % 39 - 9)
                           .FirstOrDefault(), c }) : new int[] { 0, c } )
                     .Where(c => (hex.Length % 2) == 1)
                     .Select(ca => ((byte)((ca[0] << 4) + ca[1])))
                     .Reverse().ToArray();

Still one statement. Could be made much shorter by running the replace(" ", "") on hex string in the start, but this would be a second statement.

Two interesting points with this one. How to track the character count without the help of outside variables other than the source string itself. While solving this I encountered the fact that char y.CompareTo(x) just returns "y - x" while int y.CompareTo(x) returns -1, 0 or 1. So char y.CompareTo(x).CompareTo(0) equals a char comparison which returns -1, 0 or 1.

迷鸟归林 2024-07-25 22:15:46

PHP,28个符号:

<?=pack(I,hexdec($argv[1]));

PHP, 28 symbols:

<?=pack(I,hexdec($argv[1]));
岁月流歌 2024-07-25 22:15:46

游戏迟到了,但这里有一些 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())]))

Late to the game, but here's some Python{2,3} one-liner (100 chars, needs 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())]))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文