在回答this question询问十六进制到(原始)二进制转换时,一条评论表明它可以用“5-10行C或任何其他语言”来解决。
我确信(某些)脚本语言可以实现,并希望了解如何。对于C,我们能否证明评论是真的吗?
注意:这并不意味着十六进制到 ASCII 二进制 - 特别是输出应该是与输入ASCII十六进制对应的原始八位字节流。此外,输入解析器应跳过/忽略空格。
编辑(作者:Brian Campbell)为了保持一致性,我是否可以提出以下规则?如果您认为这些内容没有帮助,请随意编辑或删除这些内容,但我认为由于对某些案例应如何运作进行了一些讨论,因此有些说明会有所帮助。
[a-fA-F \t\r\n]
之外的字符,将单个字节中的两个字符分开的空格,输入中的奇数个十六进制数字)是未定义的;任何行为(除了主动损坏用户的计算机或其他东西)都是可接受的(抛出错误,停止输出,忽略坏字符,将单个字符视为一个字节的值,都可以)答案 0 :(得分:8)
编辑 Checkers已将我的C解决方案缩减为46 bytes,由于BillyONeal的提示加上我的错误修正(不再有无限循环),因此该解决方案减少到44个字节输入,现在它只是终止循环)。请将Checkers的信息从77个字节减少到46个字节:
main(i){while(scanf("%2x",&i)>0)putchar(i);}
我有一个比上一个更好的Ruby解决方案,在 42 38 字节中(感谢Joshua Swank的regexp建议):
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
答案 1 :(得分:7)
39 char perliner
y/A-Fa-f0-9//dc,print pack"H*",$_ for<>
编辑:并不是真的接受大写,已修复。
答案 2 :(得分:7)
45字节可执行文件(base64编码):
6BQAitjoDwDA4AQI2LQCitDNIevrWMOy/7QGzSF09jLkBMAa5YDkByrEJA/D
(粘贴到扩展名为.com的文件中)
编辑:好的,这是代码。打开一个Window的控制台,创建一个名为'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
这很棘手。我不敢相信我花时间这样做。
答案 3 :(得分:6)
Brian's 77-byte C solution可以改进到44个字节。
main(i){while(scanf("%2x",&i)>0)putchar(i);}
答案 4 :(得分:4)
在Python中:
binary = binascii.unhexlify(hex_str)
一线! (是的,这是作弊。)
答案 5 :(得分:3)
编辑:此代码是在问题编辑之前很长一段时间编写的,它充实了要求。
鉴于单行C可以包含大量语句,所以几乎可以肯定没有用。
在C#中,我几乎可以肯定地用超过10行编写它,即使它在10中是 possible 。我将“解析nybble”部分从“转换为a”中分离出来。字符串到字节数组“part。
当然,如果你不关心发现不正确的长度等,它会变得容易一些。您的原始文本还包含空格 - 是否应跳过,验证等?它们是必需输入格式的一部分吗?
我更倾向于怀疑评论是在没有考虑到什么是令人愉快的,可读的解决方案的情况下做出的。
话虽如此,这是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这个词,这总是一个奖励。 )
答案 6 :(得分:2)
尔加。
我不允许按照袖手旁观估计给我打电话! ;-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。可以说它们不是必需的 - 操作系统将释放程序使用的每个资源,文件将关闭而没有任何问题,编译器将处理程序退出值。鉴于它是一次性使用脚本,它是可以接受的,但不要部署它。
两者都变成十一行,所以它不是一个巨大的增长,十行版本将包括一个或另一个,取决于哪个人可能觉得是两个邪恶的出租人。
它没有进行任何错误检查,并且它不允许空格 - 再次假设它是一次性程序,然后在运行脚本之前执行搜索/替换并删除空格和其他空格更快但是,它也不需要超过另外几行来吃白色空间。
当然,有一些方法可以缩短它,但它们可能会显着降低可读性......
哼。 只需阅读有关行长的评论,所以这里是一个较新的版本,带有一个更丑陋的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++)
每次调用时会增加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);}}
而且,再一次,进一步的混淆和比特琐事可能会导致一个更短的例子。
答案 7 :(得分:2)
当然,在一条(相当短的)线上:
my $bin = map { chr hex } ($hex =~ /\G([0-9a-fA-F]{2})/g);
答案 8 :(得分: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
答案 9 :(得分:2)
.
它的语言叫做“Hex!”。它唯一的用法是从stdin读取十六进制数据并将其输出到stdout。 十六进制!由一个简单的python脚本解析。 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"
答案 10 :(得分: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;
}
答案 11 :(得分:1)
一个31个字符的Perl解决方案:
s/\W//g,print(pack'H*',$_)for<>
答案 12 :(得分:0)
我无法将其编码到我的头顶,但是对于每两个字符,输出(字节)((AsciiValueChar1-(AsciiValueChar1&gt; 64?48:55)* 16)+(AsciiValueChar1-(AsciiValueChar1&gt; 64) ?48:55)))将十六进制字符串更改为原始二进制文件。如果你的输入字符串有0到9或A到B之外的任何东西,这会破坏性,所以我不能说它对你有多大用处。
答案 13 :(得分:0)
我知道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 )等于char比较,返回-1,0或1。
答案 14 :(得分:0)
PHP ,28个符号:
<?=pack(I,hexdec($argv[1]));
答案 15 :(得分: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())]))