只有偶数字节


64

场景

最近,您一直在使用自己喜欢的文本编辑器注意到一些奇怪的行为。最初,似乎在写入磁盘时会忽略代码中的随机字符。一段时间后,您注意到了一种模式。ASCII值奇数的字符将被忽略。经过进一步检查,您发现只有每八位为零时,才能正确写入文件。现在,您需要知道您的重要文件是否已受到此奇怪错误的影响。

任务

您必须编写一个完整的程序来确定文件是否包含奇数个字节(表明文件未损坏)。但是由于使用了文本编辑器,因此无法在源代码中写入任何奇数字节。您可以假定输入已经存在任何编码,但是您仍然必须检查每个字节,而不仅仅是字符。

输入项

您的程序将从stdin或命令行获取文件的内容或文件的路径。

输出量

如果给定文件包含一个奇数字节,则程序将向stdout输出一个真实值,而如果每八位为零,则该程序将向fsy输出一个stdout。

标准

这是代码高尔夫,是完成任务的最短程序。要成为有效提交,文件源代码中的每八位必须为零。我建议您在提交的文件中包含源代码二进制文件的副本。

有标准漏洞

测试用例

(以ASCII编码)输入:

"$&(*,.02468:<>@BDFHJLNPRTVXZ\^`bdfhjlnprtvxz|~

Output:
falsy

Input:
!#%')+-/13579;=?ACEGIKMOQSUWY[]_acegikmoqsuwy{}

Output:
truthy

Input:
LOREMIPSVMDOLORSITAMETCONSECTETVRADIPISCINGELITSEDDOEIVSMODTEMPORINCIDIDVNTVTLABOREETDOLOREMAGNAALIQVA
VTENIMADMINIMVENIAMQVISNOSTRVDEXERCITATIONVLLAMCOLABORISNISIVTALIQVIPEXEACOMMODOCONSEQVAT
DVISAVTEIRVREDOLORINREPREHENDERITINVOLVPTATEVELITESSECILLVMDOLOREEVFVGIATNVLLAPARIATVR
EXCEPTEVRSINTOCCAECATCVPIDATATNONPROIDENTSVNTINCVLPAQVIOFFICIADESERVNTMOLLITANIMIDESTLABORVM

Output:
truthy

提示

  • 明智地选择语言并非每种语言都可能会遇到这种挑战

  • Unix命令xxd -b <file name>会将文件的二进制文件打印到控制台(以及一些其他格式化内容)

  • 您可以使用ASCII以外的其他编码,例如UTF-8,只要遵守所有其他规则


2
某些语言很难读取多行输入,但是这并不意味着挑战很容易,所以可能还可以。:P输入可以为空吗?
丹尼斯

9
!#%')+-/13579;=?ACEGIKMOQSUWY[]_acegikmoqsuwy{}是禁止的可打印ASCII字符,对于任何关心的人。允许的可打印ASCII字符为" $&(*,.02468:<>@BDFHJLNPRTVXZ\^`bdfhjlnprtvxz|~
Patrick Roberts,

9
非常方便,禁止所有元音... ;-)
owacoder

4
很高兴,BF对此很有机会。
TLW

2
还要注意,如果您在DOS / Windows文件中有任何换行符,则它[CR]具有奇数位。我希望WhiteSpace是安全的,但是可惜[TAB]。如果您想上旧学校,EBCDIC会给您三个元音。
GuitarPicker

Answers:


26

GS2,4字节

dΦ("

在线尝试!

十六进制转储

0000000: 64 e8 28 22                                      d.("

这个怎么运作

      (implicit) Read all input and push it on the stack.
 Φ    Map the previous token over all characters in the string:
d       Even; push 1 for even characters, 0 for odd ones.
  (   Take the minimum of the resulting list of Booleans.
   "  Negate the minimum.

21

Befunge,36个字节

我知道这是一个古老的问题,但是我想尝试一下,因为我认为这在Befunge中将是一个有趣的挑战。

>~:0`|
>20`:>$.@
|` " "<
*8*82<^p24*

在线尝试!

它输出1输入是否损坏(即包含奇数字节),并且0确定是否正常。

说明

问题是如何在不访问/(divide)或%(modulo)命令的情况下确定奇数字节。解决方案是将值乘以128(序列28*8**),然后将结果写入运动场。在严格的标准解释器上,运动场单元格是带符号的8位值,因此奇数乘以128会被截断为-1,而偶数则变为0。

另一个技巧是在不访问g(get)命令的情况下从运动场读回-1或0 。解决方法是将值写入现有字符串序列(" ")的中间,然后执行该序列以将包含的值压入堆栈。那时,确定字节的奇数是一个简单的小于零的测试。

最后一个值得讨论的方面是输出。在错误的情况下,我们>$.在堆栈上只有一个值到达序列,因此$清除堆栈使.输出为零。在真实的情况下,我们遵循路径20`:>$.。由于2大于零,因此比较将1压入堆栈,并:进行重复复制,因此在$输出之前不会将其丢弃。


1
这可能是最新的内容,但已经是我最喜欢的答案。
小麦巫师

@WheatWizard我现在才刚刚意识到为什么这个答案受到如此多的关注。谢谢您的悬赏!
James Holderness

12

CJam(11个字节)

"r2":(~f&2b

在线演示

剥离技巧以避免奇数字节,这减少为

q1f&2b

它将读取输入,将与1进行按位AND映射,然后执行基本转换,如果所有AND均为零,则给出零。


3
这段代码很可悲:(
betseg

因为它只能有一半的字符@betseg的
罗马格拉夫

9

可打印的.COM文件,100字节

^FZjfDXVL\,LPXD$$4"PXD,lHPXDjJXDRDX@PXDjtXDH,nPXDj@XD4`@PXD,ZHPXD4,@PXD4:4"PXDH,\PXD4"PXD,hPXDRDX@P\

十六进制转储:

00000000  5e 46 5a 6a 66 44 58 56  4c 5c 2c 4c 50 58 44 24  |^FZjfDXVL\,LPXD$|
00000010  24 34 22 50 58 44 2c 6c  48 50 58 44 6a 4a 58 44  |$4"PXD,lHPXDjJXD|
00000020  52 44 58 40 50 58 44 6a  74 58 44 48 2c 6e 50 58  |RDX@PXDjtXDH,nPX|
00000030  44 6a 40 58 44 34 60 40  50 58 44 2c 5a 48 50 58  |Dj@XD4`@PXD,ZHPX|
00000040  44 34 2c 40 50 58 44 34  3a 34 22 50 58 44 48 2c  |D4,@PXD4:4"PXDH,|
00000050  5c 50 58 44 34 22 50 58  44 2c 68 50 58 44 52 44  |\PXD4"PXD,hPXDRD|
00000060  58 40 50 5c                                       |X@P\|
00000064

使用源的非常宽松的定义,即可以由人类合理键入的内容,并受EICAR标准防病毒测试文件的启发(有关更多信息,请参见Bugtraq的“让我们玩弄EICAR测试文件”)。

仅使用可打印的非奇数ASCII字节(注:影响单词的操作码往往是奇数,W位是某些操作码的lsb),它在SP处构造了一段代码(我们方便地将其设置为生成代码之后) ,执行最终落入生成的代码。

它使用以下事实:堆栈最初包含指向PSP开头的近指针,而PSP的开头包含INT 20h指令(有关更多信息,请访问https://stackoverflow.com/questions/12591673/)。

真实来源:

; we want to generate the following fragment of code

;  5E                pop si             ; zero SI (pop near pointer to start of PSP)
;  46                inc si             ; set SI to 1
; loop:
;  B406              mov ah,0x6         ; \
;  99                cwd                ; >
;  4A                dec dx             ; > D-2106--DLFF
;  CD21              int 0x21           ; > DIRECT CONSOLE INPUT
;  7405              jz end             ; > jump if no more input
;  40                inc ax             ; > lsb 0/1 odd/even
;  21C6              and si,ax          ; > zero SI on first odd byte
;  EBF3              jmp short loop     ; /
; end:
;  96                xchg ax,si         ; return code
;  B44C              mov ah,0x4c        ; D-214C
;  CD21              int 0x21           ; TERMINATE WITH RETURN CODE

 pop si             ; this two opcodes don't need to be encoded
 inc si

 pop dx             ; DX = 20CD (int 0x20 at start of PSP)
 push byte +0x66
 inc sp
 pop ax
 push si
 dec sp
 pop sp             ; SP = 0x0166
 sub al,0x4c        ; B4
 push ax
 pop ax
 inc sp
 and al,0x24
 xor al,0x22        ; 06
 push ax
 pop ax
 inc sp
 sub al,0x6c
 dec ax             ; 99
 push ax
 pop ax
 inc sp
 push byte +0x4a    ; 4A
 pop ax
 inc sp
 push dx            ; [20]CD
 inc sp
 pop ax
 inc ax             ; 21
 push ax
 pop ax
 inc sp
 push byte +0x74    ; 74
 pop ax
 inc sp
 dec ax
 sub al,0x6e        ; 05
 push ax
 pop ax
 inc sp
 push byte +0x40    ; 40
 pop ax
 inc sp
 xor al,0x60
 inc ax             ; 21
 push ax
 pop ax
 inc sp
 sub al,0x5a
 dec ax             ; C6
 push ax
 pop ax
 inc sp
 xor al,0x2c
 inc ax             ; EB
 push ax
 pop ax
 inc sp
 xor al,0x3a
 xor al,0x22        ; F3
 push ax
 pop ax
 inc sp
 dec ax
 sub al,0x5c        ; 96
 push ax
 pop ax
 inc sp
 xor al,0x22        ; B4
 push ax
 pop ax
 inc sp
 sub al,0x68        ; 4C
 push ax
 pop ax
 inc sp
 push dx            ; [20]CD
 inc sp
 pop ax
 inc ax
 push ax            ; 21
 pop sp             ; now get the stack out of the way

9

MATL,7个字节

l$Z$2\z

源代码使用UTF-8编码。因此源字节为(十进制)

108    36    90    36    50    92   122

输入是一个文件名,用单引号括起来的字符串表示。输出是文件中的奇数字节数,如果非零,则为真。

说明

l    % Push a 1. We use `l` instead of `1` to have an even value
$    % Input specificication. This indicates that the next function takes 1 input
Z$   % Input file name implicitly, read its raw bytes and push them as an array of chars
2\   % Modulo 2
z    % Number of nonzero values. This gives the number of odd bytes. Implicitly display

8

CJam,18 17 15字节

"<rj":(((*~:|X&

假定语言环境设置为Latin-1。在线尝试!

这个怎么运作

简单的解决方案如下。

q       e# Read all input from STDIN and push it as a string on the stack.
 :i     e# Cast each character to its code point.
   :|   e# Take the bitwise OR of all code points.
     X  e# Push 1.
      & e# Take the bitwise AND of the logical OR and 1.

不幸的是,这些字符qi不能出现在源代码中。要变通解决此问题,我们将动态创建上述源代码的一部分,然后评估该字符串。

"<rj"         e# Push that string on the stack.
     :(       e# Decrement all characters, pushing ";qi".
       (      e# Shift out the first character, pushing "qi" and ';'.
        (     e# Decrement ';' to push ':'.
         *    e# Join "qi" with separator ':', pushing "q:i". 
          ~   e# Evaluate the string "q:i", which behaves as explained before.

7

Pyth,20 13字节

vj0>LhZ.BRj.z

或以二进制形式:

00000000: 01110110 01101010 00110000 00111110 01001100 01101000  vj0>Lh
00000006: 01011010 00101110 01000010 01010010 01101010 00101110  Z.BRj.
0000000c: 01111010                                               z

在线尝试

这个怎么运作

           .z   all lines of input
          j     join on newline
       .BR      convert each character to binary
   >LhZ         take the last (0 + 1) characters of each binary string
 j0             join on 0
v               evaluate as an integer

如果任何字节为奇数,则所得整数为真(非零)。



4

视网膜,106字节

删除每个允许的字符,然后匹配所有剩余的字符。真实值将是找到的字符数。假值为0

`"| |\$|&|\(|\*|,|\.|0|2|4|6|8|:|<|>|@|B|D|F|H|J|L|N|P|R|T|V|X|Z|\\|\^|`|b|d|f|h|j|l|n|p|r|t|v|x|z|\||~

.

在线尝试

由于.默认情况下不匹配换行符,因此我不必删除它们。


1

Perl 5 + -p0,136字节

与其他答案类似,这会删除所有偶数字节,并保留所有奇数字节(这是事实)。

tr<�
 "$&(*,.02468:<>@BDFHJLNPRTVXZ\\^`bdfhjlnprtvxz|~€‚„†ˆŠŒŽ’”–˜šœž ¢¤¦¨ª¬®°²´¶¸º¼¾ÀÂÄÆÈÊÌÎÐÒÔÖØÚÜÞàâäæèêìîðòôöøúüþ><>d

在线尝试!


-0对换行没有任何作用。它仅确定如何拆分输入,而不删除任何字符。
与Orjan约翰森

太糟糕了。
与Orjan约翰森

@ØrjanJohansen是的,您是对的-0,我想把整个块都做一次,但这没关系,但是我无法解决这个问题……太糟糕了!我将清理这些评论。感谢您的注意!
Dom Hastings

这样就可以了吗?猜猜我应该删除一些评论。从edit diff中,我看到您现在包括了程序中的每个偶数字节。我想您可能要明确地说出来,因为并非所有这些字符都出现了(至少对我而言)。
与Orjan约翰森

@ØrjanJohansen是的!我想我已经知道了。我不认为所有其他答案也不能覆盖所有偶数字节,我认为其中一些仅适用于可打印ASCII。我非常有信心这可以满足我的需求。我还是希望如此!
Dom Hastings '18

0

Japt,10字节

ø0ôH² ®dZÄ

在线尝试!

Japt的代码页为ISO-8859-1。该代码给出了false何时以字符串形式输入本身,因此是有效的提交。

开箱及其工作方式

Uø0ôHp2  mZ{ZdZ+1

Uø      Does input string contain any element in the following array...?
0ôHp2     Range of 0 to 32**2, inclusive
mZ{       Map...
ZdZ+1       Convert the number Z to a char having charcode 2*Z+1

没有String.c(获取字符码,或在字符码上映射)是很痛苦的,但是幸运的是Number.d(将数字转换为字符)。

事实证明Japt胜过CJam,Pyth Jelly :)


在没有限制的情况下,有几种方法可以做到6个字节(再次与CJam和Jelly相提并论):

®c uÃn

Unpacked: UmZ{Zc u} n

UmZ{   Map on each char...
Zc u     Convert to charcode modulo 2
}
n      Convert the resulting string to number

"000..000"不管它长多少,都将转换为数字0(伪造)。另一方面,任何包含1的东西都将转换为非零值double,或者Infinity如果它太大(均为真)。

¬d_c u

Unpacked: q dZ{Zc u

q    Convert to array of chars
dZ{  Is something true when mapped with...
Zc u   Convert each char to charcode modulo 2

直接产生true或的更直接方法false

或者,甚至可以借助flag 实现5字节的解决方案-d

¨c u

Unpacked: q mZ{Zc u

q     Convert to array of chars
mZ{   Map...
Zc u    Convert to charcode modulo 2

      Result is array of zeros and ones
-d    Apply .some() on the resulting array
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.