验证Brainfuck程序


17

Brainfuck的另一个解析问题,但是这次……有所不同。

您正在开发Brainfuck程序的公司Infinite Monkeys Incorporated中工作,以解决各种有趣的问题(偶然地,至少是偶然,毕竟该公司创建了随机程序)。但是,看来仅执行Brainfuck的快速图灵机存在语法错误的小而昂贵的问题-生成一个,计算机便爆炸了。这可能是设计缺陷,但没有人费心去寻找它为什么会发生。

由于Turing机器(尤其是快速的机器)非常昂贵(毕竟它们具有无限的RAM成本),因此最好在执行代码之前确保程序没有任何语法错误。您的公司将要运行大量代码,因此手动验证将不起作用。编写一个程序,该程序读取用于Brainfuck的STDIN代码,如果程序有任何语法错误(例如],由于没有匹配,则是语法错误),则退出状态将退出状态设置为0(错误)以外的任何值[。如果程序完全正常,则以退出状态设置为0退出。

确保您的程序正确注意到涉及的错误[]。您不希望其他计算机爆炸,对吗?哦,请确保它尽可能的短-您的老板为简短的程序付费(因为他认为这些程序很快,还是有些东西)。哦,您不必在Brainfuck中编码(实际上,您不能,因为Brainfuck不支持退出代码),您的代码将在普通计算机上运行。

因此,正如您所看到的,您的工作是检查Brainfuck程序是否“有效”(具有成对的[]符号)。请注意,Brainfuck程序可以使用以外的其他字符[],因此请勿仅因为它具有其他命令而拒绝该程序。最小的代码获胜,但无论如何,您可能会更在乎投票。


1
不允许设置进程退出代码的语言呢?
肯德尔·弗雷

1
@KendallFrey:很简单,使用其他东西。或在GolfScript中,嵌入Ruby代码。也许这阻止了一些深奥的编程语言,但是...
Konrad Borowski

1
如果发生故障,可以将错误代码设置为非1(当然不是0)的代码吗?
marinus 2014年

@marinus:我不知道你为什么要那样,但是我认为很好。
Konrad Borowski14年

@GlitchMr:因为那样我可以GCD(a,b)代替使用0 != a || b
marinus 2014年

Answers:


6

GolfScript,18个字符

.{[]`?)},~](`91?./

如果输入中的方括号平衡,则此代码以退出代码0成功运行(并向stdout打印一些垃圾)。如果不是,则失败并返回非零退出代码,并向stderr打印错误消息,例如:

(eval):2:in `/': divided by 0 (ZeroDivisionError)

要么

(eval):1:in `initialize': undefined method `ginspect' for nil:NilClass (NoMethodError)

既然挑战没有说明对stdout / stderr的输出,所以我认为这是合格的。无论如何,您始终可以将其重定向到/dev/null

说明:

该代码{[]`?)},从输入~中除去除方括号之外的所有内容,并将结果评估为GolfScript代码。棘手的部分是,不平衡的括号在GolfScript中是完全合法的(实际上,我的代码包括其中!),因此我们需要其他方法来使代码崩溃。

我使用的技巧是将输入的副本留在堆栈的底部,将整个堆栈收集到一个数组中(使用unbalanced ])并将第一个元素移开。此时,可能会发生三件事:

  • 如果输入以unclosed结尾[,则尝试将一个元素移出一个空数组将使解释器崩溃(在这种情况下,正是我们想要的!)
  • 如果输入中的括号是平衡的,则移位后的元素将是原始输入字符串。
  • 否则(如果输入具有未打开]或未关闭[),它将是一个数组。

然后,我最初的14个字符组成的条目将移位后的值与一个字符串进行了比较,如果它是一个嵌套数组,则会崩溃。不幸的是,事实证明,在GolfScript中,将平面(或特别是空)数组与字符串进行比较也是合法的,因此我不得不改变立场。

相反,我当前的提交使用一种非常强力的方法来从字符串中分辨出数组:它取消了数组的求值并尝试查找[(ASCII码91)的第一个匹配项,当且仅当未跳过时,该值才为零变量是一个数组。如果是这样,将零除以自身会触发所需的崩溃。

附言 另外两个18字符的解决方案是:

.{[]`?)},{.}%~](n<

.{[]`?)},~]([n]+n<

las,我尚未找到解决“空数组问题”的更短方法。


这是平衡的吗?][:(即程序是否失败?)
Justin

@Quincunx:失败,应该。
Ilmari Karonen 2014年

然而,事实证明这是可以接受的[[]。我已经修复了它,费用为4个字符,它现在通过了我的所有测试。
Ilmari Karonen 2014年

如果我对您的理解正确,那么您有一个14个字符的解决方案,该解决方案仅在数组为空的情况下无法区分字符串和数组。1+将把一个空数组变成一个非空数组,一个非空数组变成一个非空数组,以及一个字符串变成字符串。
彼得·泰勒

@PeterTaylor:是的.{[]`?)},~](n<。我确实尝试过您的1+,但似乎数组需要包含数字以外的其他内容(大概是这样,当解释器尝试递归比较字符与数组/字符串时,解释器将崩溃)。使用n+也不起作用,因为它将数组强制为字符串。[n]+ 确实有效,但仍然使我处于18个字符的位置。
Ilmari Karonen 2014年

17

Brainfuck 76字节

>>+[<+++++++++[->---------<]+>-[--[[-]<->]<[<[->-]>[<+]<]>]<[-<+>]+>,]<<[<+]

如果方括号不平衡,这将使bf解释器/编译器运行时失败,并且其中一些具有退出代码来反映这一点,这是没有关系的。

需要eof = 0,包装值和单元格的finit数

在Ubuntu中,您可以使用解释器bfsudo apt-get install bf

% echo '[[[]' | bf -n bf_matching.bf
Error: Out of range! Youwanted to '<' below the first cell.
To solve, add some '>'s at the beginning, for example.
an error occured
% echo $? 
5
% bf -n bf_matching.bf < bf_matching.bf
% echo $?
0

5
我喜欢你如何使用Brainfuck,即使这个问题说那是不可能的。
2014年

哦,哇 老实说,我很惊讶。我以为这是不可能的,但事实并非如此。
Konrad Borowski14年

1
@xfix:Brainfuck是图灵完整的,因此它可以做任何事(考虑到I / O约束。)
marinus 2014年

2
@marinus Turing完成仅意味着它可以进行所有计算。BrainfuckTuring完全没有I / O,因为您可以运行一个程序,该程序可以计算任何计算结果,并在运行后通过检查其内存来查看结果。没有I / O的BF将使人们不那么感兴趣,因为它将难以制造实用程序。例如我永远都无法做我轻快的口译员
Sylwester 2014年

14

Befunge 98 - 26 31 20 19个字符

~:']-!\'[-!-+:0`j#q

摆脱了一些巨大的条件。现在该程序的工作方式如下:

~:   read an input char and duplicate it

']-! push a 1 if the char is the ] char, 0 otherwise

\    swap the comparison value for the duplicated input char

'[-! push a 1 if the char is the [ char, 0 otherwise

-    subtract the two comparison values. If the second one is 1, the first is 0, 
     so the result is -1. Else if the second one is 0, the first is 1 and the result is
     1. Else, the first and the second are both 0 and the result is 0

+    Add the number to the counter (which is 0 if there is none already)

:0`  test if the counter is positive (that'd mean an invalid program). Pushes a 1 if 
     positive, 0 otherwise.

j#q  if the counter is positive, then this jumps to the q. Otherwise, it skips the q 
     and continues to the ~ at the beginning of the line. If there are no more chars in
     the input, then the IP will be sent back to the q. 

q退出程序并弹出最高值作为错误值。误差值将是-1 1,如果有太多]的0,如果他们是平衡的,并积极负,如果有太多[的。如果号码是负,那么很多这个数字的绝对值]需要的平衡方案。

编辑:切换增量和减量。[用于增加计数器并]用于减少计数器。通过切换它,我节省了1个字符,因为对于退出条件,我只需要检查计数器是否为正,而不是负。


旧版本

~:'[-!j;\1+\#;']-!j;1-#;:0\`j#q

该代码的工作方式如下:

~    read one char of input
:    duplicate it
'[-! push 1 if the character is [, 0 otherwise
j    jump that number of characters
;    skip until next ;
\1+\ increment counter

similarily for ].

#q when end of input is reached, ~ reflects the IP back. q ends the program with the error value on the stack.

编辑:意识到此接受的输入,例如][,现在只要计数为负就结束,使用

:0\`j


@JoKing这是相当不错的,使用之间的距离[,并]做两个比较。
贾斯汀

6

J(38 35)

exit({:+.<./)+/\+/1 _1*'[]'=/1!:1[3

说明:

  • 1!:1[3:读标准输入
  • '[]'=/:创建一个矩阵,其中第一行是[输入中s 的位掩码,第二行是]s。
  • 1 _1*:将第一行乘以1,将第二行乘以-1。
  • +/:将矩阵的各列加在一起,得出每个字符的增量缩进
  • +/\:创建一个连续的总计,在每个字符处给出缩进级别
  • ({:+.<./):返回最后一个元素({:)和最小元素(<./)的GCD 。如果所有的花括号都匹配,则这两个花括号都应该匹配,0以便返回0。如果花括号不匹配,它将返回一个非零值。
  • exit:将退出值设置为该值并退出。

不错的故障...-
克里斯·卡什韦尔

6

红宝石(64)

exit $<.read.tr('^[]','').tap{|x|0while x.gsub!('[]','')}.empty?

以前(68)它是:

exit ARGF.read.tr('^[]','').tap{|x| 0 while x.gsub!('[]','')}.empty?

另一个等效的解决方案使用

exit $<.read.tr('^[]','').tap{|x|0while x.gsub!('[]','')}.size>0

不能size单独使用,因为当不平衡括号的总数为256的倍数时,它将产生假阴性(!!!)


这是代码高尔夫。我确定您可以在此处删除一些空格。Ruby在某种程度上对空格敏感,但是在许多情况下它会忽略它。首先,您不需要在=运算符附近使用空格。
Konrad Borowski14年

更好的版本(某种程度上受sed + tr解决方案的启发)。我不确定我会比这更好。至少它只有4个空格!
2014年

1
但是,我可以删除其中两个。
Konrad Borowski

2
我认为0可以围绕的空间。
marinus 2014年

很棒的太空技巧,谢谢!
2014年

5

Perl,30个字符

您可以使用的基本Perl递归正则表达式:

perl -0ne 'exit!/^(([^][]|\[(?1)\])*)$/'

对于那些不熟悉此处使用的命令行参数的人:-0允许出于文件输入的目的设置行尾字符;使用-0不带参数的行尾字符设置为EOF。-n自动将输入(在这种情况下为整个文件)读入$_预先。

如果正则表达式匹配,则返回一个真值,对于退出代码,该值取反0。否则,错误的返回值将产生退出代码1。


猜猜我将不得不更好地解决我的问题,才能击败这30个字符的解决方案。
贾斯汀

那里。我的解决方案现在比以前短得多。不错的解决方案。+1
贾斯汀

4

bash(tr + sed)-42

[ -z `tr -Cd []|sed ":a;s/\[\]//g;t a"` ]

如果您不介意错误消息,则可以删除之间的最后一个空格`]以获取长度41。


除非我什么都没错过,否则您会无用的cat$()(也"[]"可以写成[])。我接受了这个答案,但是在我看到长度有所改善之前,我不会对此表示赞同,因为虽然很短,但对于bash来说可能会更短。
Konrad Borowski14年

好吧,实际上我不太了解Shell脚本。我无法完成大部分工作。我$()用反引号代替,并执行了"[]"-> []您的建议。
shiona 2014年


1
我本来可以尝试的剑却失败了,但是我错了。
shiona 2014年

3

Perl(56个字符)

$/=0;$r=qr/[^][]*(\[(??{$r})\])*[^][]*/;<>=~m/^$r$/||die

显而易见的Perl解决方案:递归正则表达式。不幸的是,这是一个相当冗长的构造。


3

哈斯克尔(143)

import System.Exit
f=exitFailure
v c []|c==0=exitSuccess|True=f
v c (s:t)|c<0=f|s=='['=v(c+1)t|s==']'=v(c-1)t|True=v c t
main=getContents>>=v 0

到jgon:使用2个防护似乎比if-then-else更密集。另外,我认为您不会检查方括号的顺序是否正确(“] [”通过)


哦,哇,今天才指出这条评论。修复了我的代码,但是不错,后卫确实更密集(+1)。
jgon

3

C,73 64个字符

感谢面包箱的建议(尽管这可能需要使用低位字节序):

i;main(c){while(read(0,&c,1)*(i+1))i+=(c==91)-(c==93);return i;}

怎么运行的:

  • 隐式int全局i初始化为0
  • c 成为一个隐式int argc(初始化为1,但我们不在乎,只要不设置更高的位)
  • read(0,&c,1)将单个字符读入c的低字节(在Little-endian架构上),并在EOF返回0;i+1 != 0除非平衡括号中的报价为-1;否则 将它们相乘就像一个(安全的)布尔值,并且比&&
  • c==91计算结果为1 '[',并且c==93计算结果为1']'。(可能有一些比较麻烦的小技巧,但是我什么都没想到。)
  • return i如果状态为0,则退出,状态码为0,否则为非零。从技术上讲,返回-1违反了POSIX,但实际上没有人在乎。

先前版本:

main(i){char c;i=0;while(read(0,&c,1)*(i+1))i+=(c==91)-(c==93);return i;}

使用getchar()而不是读取将缩短代码,并允许您(隐式)int代替char变量。还请记住,全局变量会自动初始化为零。
面包箱2014年

谢谢,我忘记了getchar()。不过,不确定全局初始化有何帮助-与使用隐式argc一个字符相比,定义一个全局int我需要更多的字符。
蓬松的2014年

1
全局变量也可以是隐式的。在函数外部c;定义一个全局int。
面包盒

同时,至少使用这种方法,getchar(c)最终没有使其变得更短,因为需要以某种方式对它进行> = 0的测试,并且不能保证将c的隐式int传递给read()。由于字节顺序工作。
蓬松的2014年

][呢 我确定它不平衡。您是否不必至少跟踪一次负值?
vsz 2014年

2

卢阿(56岁)

os.exit(("["..io.read"*a".."]"):match"^%b[]$"and 0 or 1)

"^%b[]$"这是什么?你可以解释吗?当然,这不是正则表达式吗?
Cruncher 2014年

@Cruncher:不是。它是Lua模式,而不是正则表达式(Lua模式与正则表达式类似,但不是)。在这种情况下,它会匹配字符串(^)的开头,的平衡集[以及之间]的任何内容(%b[]),和字符串的结束($)。
Konrad Borowski14年

1

总局 55

0→O:0→X[`I@I="[":X+1→X@I="]":X-1→X@X<0:1→O@!!Ig;e]l;e~O

未命中 []

使用0停下来。


1

MATHEMATICA,88个字符

s = "[ [ my crazy code ] [ don't explode please! [] [ :)Ahh) ]  [] []]]";

r=StringReplace;
StringLength@FixedPoint[r[#,"[]"-> ""]&,r[s,Except@Characters["[]"]-> ""]]

使用s name like RegularExpression` 函数,StringLength我永远无法在Mathematica中赢得文本代码高尔夫上下文!:)
Murta 2014年

我知道您的意思:) ToCharacterCode比现在还要长ord... PS:设置退出代码呢?
2014年

Length[StringCases[s,"["|"]"]//.{x___,"[","]",y___}:>{x,y}]
alephalpha 2014年

1

红宝石, 59 58

扫描左括号和右括号,分别[为1和]-1,如果计数低于0,则退出。

b=0
$<.read.scan(/\]|\[/){exit 1if(b+=92-$&.ord)<0}
exit b

1
投票并缩短了一个字符(以防万一,我删除了空格exit 1)。
Konrad Borowski14年


1

图灵机代码,286 276字节

同样,我使用此处定义的规则表语法

0 * * l 1
1 _ ! r Q
5 _ _ r 5
5 * * * W
W [ ! l E
W ] ! l T
W _ _ l I
W * ! r *
E ! ! l *
E * * * R
R _ [ r O
R * * l *
T ! ! l *
T * * * Y
Y _ _ r U
Y * * l *
U [ _ r O
U ! ! * halt-err
I ! ! l *
I _ _ r halt
I * * l halt-err
O ! ! r Q
O _ _ l I
O * * r *
Q ! ! r *
Q * * * W

终止状态halt以接受输入并halt-err拒绝输入。


halt-err可以更短,halt*例如。
暴民埃里克(Erik the Outgolfer)

1

Pyth,25个字节

Ilzv::z"[^[\]]"k"]\[""],[

在线尝试!

Python 3翻译:
import re
z=input()
if len(z):
 print(eval(re.sub("]\[","],[",re.sub("[^[\]]","",z))))

1

哈斯克尔(167

这样做主要是为了娱乐,如果有人对如何使其更短有任何建议,我很高兴听到他们的声音:)

import System.Exit
p x y b|b=x|True=y
main=getContents>>=(return.all (>=0).scanl (\v->p (v-1) (v+1).(==']')) 0.filter (`elem`"[]"))>>=p exitSuccess exitFailure

编辑:修复了在注释中向我指出的一个问题(增加了11个字节)。

编辑2:创建辅助功能,用于使用受user13350启发的防护测试谓词,并删除8个字节。



@ user202729这是一个很好的观点,那是超级粗心。可以肯定的是现在已经修复。
jgon

1

Stax14 11个字符

╬Äτ↔EªÉs «Ü

运行并调试

将@recursive记入-3个字节。

ASCII等效项:

.[]Y|&{yz|egp!

删除除以外的所有字符[],然后删除[]直到字符串不再更改。1如果最后一个字符串为空,则返回。


1
真好 您可以使用.[]|&过滤字符,然后重新使用原义11
递归
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.