【问题标题】:Code golf - hex to (raw) binary conversion代码高尔夫 - 十六进制到(原始)二进制转换
【发布时间】:2010-10-22 03:44:06
【问题描述】:

在回复this question 询问十六进制到(原始)二进制转换的问题时,一条评论建议它可以用“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 行)。

【问题讨论】:

  • 5 行可以有多宽? ;-p
  • 我一般认为行长度为 80 个字符;我认为对于代码高尔夫游戏来说,这是一个合理的数字。
  • 啊!高尔夫什么时候变成了“编写一个冗长、可读的程序来解决这个问题”?所有 20 行 700 个字符的解决方案是什么?
  • 三忌是新鹰
  • @Daniel - 最初是我的问题 - 我对 Brian 的“澄清”感到满意

标签: binary hex code-golf


【解决方案1】:

编辑:此代码是在充实要求的问题编辑之前很长时间编写的。

鉴于单行 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 的使用,这始终是一个奖励。)

【讨论】:

  • 我认为这不会忽略空格,据我所知,它不适用于奇数长度的字符串...
  • 不,确实没有。这个问题并不清楚确切的要求。
  • 我不是 .NET 程序员,但 Console.WriteLine 不是在末尾添加额外的行终止符吗?如果您尝试编写二进制输出,这似乎是个坏主意。它是否对字符串中的换行符进行行尾翻译?对二进制输出也不利。
  • @Brian:Console.WriteLine 调用用于测试目的 - 它实际上将二进制数据转换回 ASCII 十六进制字符串(对 BitConverter.ToString 的调用),因为这是一种简单的测试方法ParseHex 方法是正确的。 ParseHex 方法是解决方案的核心。
【解决方案2】:

在 Python 中:

binary = binascii.unhexlify(hex_str)

一条线! (是的,这是作弊。)

【讨论】:

  • 我会给你一个+1,因为你实际上尝试打高尔夫球(并且做了短暂的),但你没有添加你需要的'import binascii'来让它工作。另外,我认为您需要代码来读取输入并将其打印出来。
  • 我实际上在发布此内容时考虑添加导入语句,但决定给我的短语“这是作弊”赋予隐藏的双重含义。
  • -1,它不起作用(必须导入模块,你知道:P)并且不从标准输入读取/写入标准输出。
  • @Brian 很好地接受了答案,也忽略了包括 stdio.h,即使它使用了使代码行为未定义的 scanf (vararg)。太糟糕了,这个不起作用:((不是说我不喜欢你的其他c解决方案。我认为它很整洁:))
  • @shylent:在添加任何额外规则之前,我以这种方式发布,例如需要标准输入/标准输出的东西。 :P
【解决方案3】:

我无法在脑海中对此进行编码,但是对于每两个字符,输出 (byte)((AsciiValueChar1-(AsciiValueChar1>64?48:55)*16)+(AsciiValueChar1-(AsciiValueChar1>64 ?48:55))) 将十六进制字符串更改为原始二进制文件。如果您的输入字符串不是 0 到 9 或 A 到 B,这将非常糟糕,所以我不能说它对您有多大用处。

【讨论】:

    【解决方案4】:

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

    【讨论】:

    • 不错的 (0-9,A-F,a-f) -> (0-15) 转换!我从来没有想过使用 and-ing 和 0xF 来处理 A-F 和 a-f 情况。
    【解决方案5】:

    呸。

    您不可以根据我的即兴估算给我打电话! ;-P

    这是一个没有奇怪格式的 9 行 C 版本(好吧,我承认 tohex 数组最好分成 16 行,这样你就可以看到哪些字符代码映射到哪些值......),而且只有除了一次性脚本之外,我不会部署 2 个快捷方式:

    #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。可以说它们是不需要的——操作系统将释放程序使用的所有资源,文件将毫无问题地关闭,编译器将处理程序退出值。鉴于它是一次性使用脚本,可以接受,但不要部署它。

    两者都变成了 11 行,所以无论如何这并不是一个巨大的增长,而 10 行版本将包括一个或另一个,这取决于一个人可能会觉得是两害相权。

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

    当然,有一些方法可以缩短它,但它们可能会显着降低可读性...

    哼。 请阅读关于行长的评论,所以这里有一个更新的版本,它带有一个更丑陋的 hextonum 宏,而不是数组:

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

    再一次,进一步的混淆和比特旋转可能会导致一个更短的示例。

    【讨论】:

    • char hextonum[256] = { 0 } 等同于数组初始化程序中的内容。
    • 与查找表的良好调用,这也是我想到的第一件事。
    • 不,这不是 FryGuy,他使用 ASCII 查找表将十六进制数字转换为二进制等价物。再向右滚动一些。 :)
    • @FryGuy - 我想如果你仔细看,你会发现数组有 21 个条目不是 0...
    • FryGuy 提出了一个观点——我认为他可以在最后一个非零条目之后放弃所有内容,让编译器为他填写 ASCII 字符 103-255 为 0。 (不过,我可能完全错了)
    【解决方案6】:

    我知道 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 比较。

    【讨论】:

    • 阻止评估 - 不错的错字
    【解决方案7】:

    edit Checkers 已将我的 C 解决方案减少到 46 bytes,然后由于 BillyONEal 的提示加上我的错误修复(不再有错误输入的无限循环,现在它只是终止循环)。请感谢 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 字节(我相信这可以改进):

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

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

    【讨论】:

    • 使用 scanf() 将输入读入 char 的版本不能很好地工作;我认为您应该将其编辑掉,只保留(添加coolnes)使用“魔术” i 整数的那个。
    • scanfs 到 char 的版本对我来说很好,除了我提到的未知字符的无限循环。你还有别的问题吗?我想保留它,以展示 Checkers 是如何设法将其减少到 46 个,然后是 44 个字符。
    • for 循环怎么样? main(i){for(;scanf("%2x",&i)>0;putchar(i))} 我错过了分号吗?目前我这里没有编译器...
    • 您可以将正则表达式简化为 \S\S。
    • 不要忘记 ruby​​ 全局变量:$<.read.scan>
    【解决方案8】:

    Perl

    当然是一行(相当短的):

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

    【讨论】:

      【解决方案9】:

      哈斯克尔:

      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
      

      【讨论】:

        【解决方案10】:

        Brian's 77-byte C solution 可以提高到 44 字节,这要归功于 C 对函数原型的宽容。

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

        【讨论】:

        • main(i){while(scanf("%2x",&i)>0)putchar(i);} 可以将 !=-1 替换为 >=0 并少一个字符:P
        • 干得好!哇,45 字节;我怀疑你能不能比 C 语言做得更好。我们可以得到任何低于 C 的脚本语言吗?
        • 哦,实际上是 44 个字符,如果你使用 >0 而不是 >=0,这也消除了错误输入时的无限循环。
        • 根据 cmets 更新。
        【解决方案11】:

        39 char perl oneliner

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

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

        【讨论】:

        • 非常好,比之前发布的 Perl 版本更好,因为它也支持标准输入/标准输出。
        【解决方案12】:

        45 字节可执行文件(base64 编码):

        6BQAitjoDwDA4AQI2LQCitDNIevrWMOy/7QGzSF09jLkBMAa5YDkByrEJA/D
        

        (粘贴到扩展名为 .com 的文件中)

        编辑:好的,这是代码。打开一个窗口的控制台,创建一个名为“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
        

        按回车键,'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
        

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

        【讨论】:

        【解决方案13】:

        31 个字符的 Perl 解决方案:

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

        【讨论】:

          【解决方案14】:

          PHP,28 个符号:

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

          【讨论】:

            【解决方案15】:
            .
            

            它是一种叫做“Hex!”的语言。它的唯一用途是从标准输入读取十六进制数据并将其输出到标准输出。 十六进制!由一个简单的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"
            

            【讨论】:

              【解决方案16】:

              游戏晚了,但这里有一些 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-01-20
                • 1970-01-01
                • 2016-02-09
                • 1970-01-01
                • 1970-01-01
                • 2014-10-30
                • 2020-06-27
                • 2012-05-28
                相关资源
                最近更新 更多