我已经使用bf-x86编译器和相当大的JSON文件测试了以下代码。我相信代码可以在有效的(!)JSON输入上正常运行。
这是我的第二个JSON格式化程序,也是我在Brainfuck中的第一个代码。尽管我已经尽力做到最好,但我对最佳实践和代码风格一无所知。
兴趣点:格式化
注释的值
使用的算法和首选替代方法的值
程序的核心是带有switch语句的读取循环:
<
#!/usr/bin/brainduck
This program is a JSON formatter
It takes a valid(!) JSON input and outputs formatted JSON
Memory layout used:
0 input
1 input copy
2 switch flag
3 input copy for switch
4 indent
5 indent copy
6 indent copy
Zero separated strings
7 zero
8 placeholder
? zero
? JSON specific chars
? zero
? "while inside string" memory
Zero separated strings
Filling placeholder " " (two spaces)
>>>>>>>
> >++[-<++++++++++++++++>]<
> >++[-<++++++++++++++++>]<
>zero
Filling JSON specific chars after placeholder
> 0a \n ++++++++++
> 20 space >[-]++[-<++++++++++++++++>]<
>zero
Back to cell 0
<[<]<[<]<<<<<<<
Initial input
,
while input [
Input in cell 0 already
Zeroing memory in cells 1 2 3
>[-]>[-]>[-]<<<
Copying input to cells 1 3
[-
>+<
>>>+<<<
]
switch flag = on
>>+
>
The Switch
switch cell 3
\t ---------[
\n -[
\r ---[
space -------------------[
" --[
comma ----------[
: --------------[
( square bracket ---------------------------------[
) square bracket --[
{ ------------------------------[
} --
default [[-]<-
in each switch case <.> outputs current char
>]
case '}' <[-
Newline >>>>>>[>]>.
Back to cell 2 [<]<[<]<<<<<
Decrementing indent >>-
Copying indent [->+>+<<]
Placeholders >>[->>[.>]<[<]<]
Copying indent back <[-<+>]
Back to cell 2 <<<
Closing brace <.>
]>]
case '{' <[-
Opening brace <.>
Newline >>>>>>[>]>.
Back to cell 2 [<]<[<]<<<<<
Incrementing indent >>+
Copying indent [->+>+<<]
Placeholders >>[->>[.>]<[<]<]
Copying indent back <[-<+>]
Back to cell 2 <<<
]>]
case closing square bracket <[-
Newline >>>>>>[>]>.
Back to cell 2 [<]<[<]<<<<<
Decrementing indent >>-
Copying indent [->+>+<<]
Placeholder >>[->>[.>]<[<]<]
Copying indent back <[-<+>]
Back to cell 2 <<<
Closing bracket <.>
]>]
case opening square bracket <[-
Opening bracket <.>
Newline >>>>>>[>]>.
Back to cell 2 [<]<[<]<<<<<
Incrementing indent >>+
Copying indent [->+>+<<]
Placeholders >>[->>[.>]<[<]<]
Copying indent back <[-<+>]
Back to cell 2 <<<
]>]
case ':' <[-
Colon <.>
Space >>>>>>[>]>>.
Back to cell 2 [<]<[<]<<<<<
]>]
case comma <[-
Comma <.>
Newline >>>>>>[>]>.
Back to cell 2 [<]<[<]<<<<<
Copying indent >>[->+>+<<]
Placeholder >>[->>[.>]<[<]<]
Copying indent back <[-<+>]
Back to cell 2 <<<
]>]
case '"' <[-
Quotation mark <.>
Going to string memory after JSON chars
>>>>>>[>]>[>]>
Memory layout:
0 string loop flag
1 switch flag
2 string input
3 escape flag
4 temp
Zeroing memory
[-]>[-]>[-]>[-]>[-]<<<<
string loop flag = on
+
while string loop flag [
Echo string char >>,.
if escape flag >>[-]+<[
escape flag = off
[-]
>-<
]
else >[-
switch cell 2 <<<+>
" ----------------------------------[
\ ----------------------------------------------------------
default [<->[-]]
case '\' <[-
escape flag = on
>>+<<
]>]
case '"' <[-
Unescaped quote ends string
string loop flag = off
<->
]>
>>
]<<<<
]
Back to switch cell
<<[<]<[<]<<<<<
]>]
Skipping original formatting
case space <[-]>]
case '\r' <[-]>]
case '\n' <[-]>]
case '\t' <[-]>
Back to cell 0
<<<
Next char
,
]
代码压缩产生了923个字节长的程序。很好用的控制台应用程序:
$ cat example.json
{"foo":"bar","baz":["\"rogue\" {s}tring",1,2,3.2e1]],"t":true,"f":false,"n":null}
$
$ ./pretty-json < example.json
{
"foo": "bar",
"baz": [
"\"rogue\" {s}tring",
[
1,
2,
3.2e1
]
],
"t": true,
"f": false,
"n": null
}
好,祝大家好运!
#1 楼
得益于其全面的文档,您的代码的结构令人印象深刻,易于阅读。我注意到我要做的第一件事就是初始化空格字符。您的代码为:
> 20 space >[-]++[-<++++++++++++++++>]<
由于内存清零,因此可以省略
[-]
当进程开始时。在某些情况下,可以消除相邻的
<>
或><
,但该工作应交给编译器,因为它们是众所周知的优化技术。清楚地表达其意图的代码比完成编译器的工作更为重要。 Back to cell 0
<[<]<[<]<<<<<<<
由于恰好有2个JSON特定字符,因此我将用更简单的
[<]
替换了第一个<<
。这也适用于其他情况,其中代码跳过了以零结尾的字符串。当我看到占位符字符串时,我想到了将缩进字符串存储为纯数字。我不知道这是否会使代码整体更简单。您尝试过吗?
将缩进字符串表示为数字还可以防止缩进字符串由空格和制表符之外的其他字符组成。使用其他字符可能会生成格式错误的JSON。
与其将其命名为“占位符”,不如将其更精确地命名为“缩进字符串”,但很容易将其与“缩进”混淆,然后将其与必须命名为“缩进深度”。
存储单元5和6都包含“缩进副本”。为了防止混淆,可以对此进行详细记录。很高兴知道这些单元格中的每个时间点包含有效数据。
在这两个开关块中,您依赖于VM允许数字下溢,这是不能保证的。我本来希望能以最可移植的方式处理这种情况的代码,但是我想那会更加复杂。
这行使我感到困惑,因为它将代码嵌入到字符串中,否则看起来像是注释。您没有在描述中说明您打算参加“欠人脑的竞赛”,其余代码看起来都不是这样。还是呢?这很难说。
in each switch case <.> outputs current char
我将这两行合并为一行保持单元2上的数据指针一致,从而使第二行中的注释变得多余。如上所述,我将第一个
Newline >>>>>>[>]>.
Back to cell 2 [<]<[<]<<<<<
替换为一个简单的[<]
,使其与上一行中的单个<
对称。即使这意味着该代码不会单独反映JSON格式的每个语法规则。在这种情况下,获得代码简化的价值更大。总体而言,这是精心设计程序,内存管理,算法,设计模式和效率的一个很好的例子。
评论
\ $ \ begingroup \ $
哇,这是一个很棒的评论,非常感谢!关于[>]的使用:我想支持几个空格作为占位符(例如2或4),这就是我将零终止字符串设为零的原因。
\ $ \ endgroup \ $
–sineemore
20 Jan 16 '20 at 18:31
\ $ \ begingroup \ $
是的,是的,在每种情况下<。>输出当前的char实际上是不熟练的Brainfuck竞赛参与^。^我根本无法抗拒
\ $ \ endgroup \ $
–sineemore
20 Jan 16 '18:32
评论
哇!这可能是到目前为止我所见过的最有用的Brainfuck程序。肯定击败了我的FizzBuzz。我将此放在我的Brainfuck评论TODO列表中。@SimonForsberg,哇,谢谢回复!我浏览了FizzBuzz和其他一些Brainfuck问题,以了解样式和格式的基本概念。