编程一个原始世界


87

让我们将原始程序定义为本身没有任何错误,但是如果您通过删除任何连续的N个字符的子字符串来修改它会出错的程序,其中1 <= N < program length

例如,三个字符的Python 2程序

`8`

是一个原始程序谢谢Sp),因为删除长度为1的子字符串所导致的所有程序都会引起错误(实际上是语法错误,但是任何类型的错误都可以):

8`
``
`8

并且由于删除长度为2的子字符串而产生的所有程序也会导致错误:

`
`

例如,如果`8曾经是一个没有错误的程序,那么`8`它将不会是原始的,因为所有删除子字符串的结果都必须出错。

在此挑战中,您的任务是编写最短的原始程序,该程序无需输入,但可以输出以下五个单词中的任何一个:

world
earth
globe
planet
sphere

您选择哪个单词完全取决于您。唯一的单词加上可选的尾随换行符应打印到标准输出(或您的语言的最接近替代品)。以字节为单位的最短程序获胜。

笔记:

  • 需要一个独立程序,而不是一个功能。
  • 这些单词区分大小写;输出WorldEARTH不允许。
  • 编译器警告不算作错误。
  • 出错的子程序可以接受输入或给出输出,或执行其他任何操作,只要它们始终最终出错即可。

这是一个堆栈片段,将列出给定潜在原始程序的哪些程序需要出错:

<script src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js'></script><script>function go() { var s = $('#i').val(), e = []; for (var i = 1; i < s.length; i++) { for (var j = 0; j <= s.length - i; j++) { e.push(s.substring(0, j) + s.substring(j + i)); } } $('#o').val(e.join('\n---\n')); }</script>Program:<br><textarea id='i' rows='16' cols='80'>`8`</textarea><br><button onclick='go()' type='button'>Go</button><br><br>Programs that should error: (--- separated)<br><textarea id='o' rows='16' cols='80'></textarea><br>


1
@geokavel是的。捕获异常意味着它不再是错误。
加尔文的爱好2015年

33
已删除答案的数量是未删除答案的两倍。那是成就!
DLosc 2015年

1
程序可以读取自己的源代码吗?
谢尔瓦库2015年

2
在哪里可以看到“封闭但没有雪茄”答案的坟墓和他们的评论?
六。

1
@Vi。获得2,000个代表,以便您可以查看已删除的帖子
ThisSuitIsBlackNot

Answers:


46

轨道,24字节

$'main'    #
 -[world]o/

认为这可行。它既简短又可读(就Rail而言)。

  • 如果删除的子字符串包含$'main'我们的任何部分,则得到Internal Error: Crash: No 'main' function found
  • 如果删除的子字符串包含#,则程序无法干净退出,因此它将始终以结尾Crash: No valid move。我认为无法删除子字符串以使轨道形成有效(无限)循环。
  • 如果已删除的子字符串位于的前面#,则它将与轨道的末端断开连接,因此火车将坠毁(与上述错误相同)。
  • 如果删除的子字符串在之后#,则还将#从的末尾(甚至可能从入口点到轨道的开头)断开$。因此再次出现相同的错误。

至于实际的程序:每个Rail程序都需要有一个$'main'(或更长的变体,但我们在这里打高尔夫球)作为该功能的切入点,并且火车从行驶$的东南方向开始。不过,第一行中的所有内容都可以成为轨道的一部分,因此删除'main'轨道是:

$          #
 -[world]o/

-/仅仅是轨道碎片,我们需要让火车把这些45°转角。

[world]推动worldo打印字符串。#标志着轨道的尽头-安全终止Rail程序的唯一方法。

有趣的是,这种解决方案是唯一可行的,因为Rail允许轨道通过main线路-如果不可能#,则在第一行换行之后,并且代码总是可以缩短为

$'main'
 #

这是不执行任何操作的有效程序。(介于'和之间的非空格字符#不会对此造成影响。)

同样也很有趣:如果我只是打高尔夫球,那么任务打印world就不会更短或更简单:

$'main'
 -[world]o#

4
如果我删除[和]之间的任何字符怎么办?
MartinLütke'15

@MartinLütke它会断开/#
马丁·恩德

2
@MartinLütke您不能仅除去括号,因为它们不连续。
加尔文的爱好

如果删除两行之间的换行符怎么办?
六。

1
@Vi。这与$轨道的起点断开了连接,因此火车立即坠毁(Rail希望轨道沿的东南方向行驶$)。
马丁·恩德

43

功能可按186个中UTF-16 136字节)

╔══════════════╗
║19342823075080╟
║88037380718711║
╚══════════════╝

该程序打印“世界”。

您从中删除的大多数子字符串将阻止它成为一个完整的框,解析器将抱怨该框。留下完整框的唯一可能清除方法是:

 ╔══════════════╗
|║19342823075080╟  (remove this whole line)
|║88037380718711║
 ╚══════════════╝
 ╔══════════════╗
 ║|19342823075080╟   ← substring starts at | here
 ║|88037380718711║   ← substring ends at | here
 ╚══════════════╝
... ↕ or anything in between these that removes a whole line’s worth ↕ ...
 ╔══════════════╗
 ║19342823075080|╟   ← substring starts at | here
 ║88037380718711|║   ← substring ends at | here
 ╚══════════════╝
 ╔══════════════╗
|║19342823075080╟
 ║88037380718711║  (both lines entirely)
|╚══════════════╝
 ╔══════════════╗
 ║19342823075080╟
|║88037380718711║  (remove this whole line)
|╚══════════════╝

其中大多数都去除了盒子右上角的悬空端,即输出连接器。没有这个松散​​的结局,此框只是一个注释:

╔══════════════╗
║88037380718711║
╚══════════════╝

这不再是有效的程序,因为解析器期望一个程序只有一个输出:

错误:源文件不包含程序(程序必须具有输出)。

留下输出连接器的唯一可能性是上述情况中的最后一个,这使得该问题成为可能:

╔══════════════╗
║19342823075080╟
╚══════════════╝

但是,此数字无法在Funciton深奥的UTF-21中编码有效的Unicode字符串。尝试运行此命令,您将获得:

未处理的异常:System.ArgumentOutOfRangeException:有效的UTF32值介于0x000000和0x10ffff之间(包括0x000000和0x10ffff),并且不应包含代理代码点值(0x00d800〜0x00dfff)。

因此,该程序是原始的。


3
我觉得您在最后一种情况下很幸运(不是偶然获得有效的Unicode序列很容易,但仍然...)
Esolanging Fruit

34

Visual C ++- 96 95字节

#include<iostream>
#define I(a,b)a<<b
int main()I({std::cout,I('w',I('o',I('r',I('l','d';)))))}

特性:

  1. int main()没有编译错误,您将无法删除其中的任何部分。
  2. 你不能删除修改宏扩展AT ALL,删除a所有手段main()从来没有得到{,删除b所有意味着我们这行不以结束;,除去<手段std::cout<'w'导致错误,并去除<<病因std::cout'w''w''o'等等。
  3. 您不能从宏定义或调用中删除参数,该定义的唯一有效名称是I(a)I(b)该名称永不匹配,I并且会扩展到before (;另一方面,请使用I(,cause <<<<,并,)删除分号(除非出现其他错误)。
  4. 您不能删除所有的一部分,而std::cout不必碰到Lead <<,因此一开始就不能删除任何#include<iostream>一个而没有编译错误。
  5. 您无法删除单个字符的任何部分,字符''为空,并且出现'w,等等,请尝试将所有内容都变成一个字符。
  6. 您不能删除宏的左/右侧而不留太多)(留在另一侧,例如,您不能执行I('w',I('r'

使用Visual C ++在线编译。

再一次,这不是一个详尽的证明。如果您认为可以无节制地工作,请务必让我知道。

以前的版本使用了截然不同的方法,被证明不是原始的,因此我删除了那些分数。


验证:

以下程序已使用clVisual C ++ 2010 的编译器确认该版本是原始版本。希望我早点写出来:

#include <fstream>
#include <iostream>
char *S = "#include<iostream>\n#define I(a,b)a<<b\nint main()I({std::cout,I('w',I('o',I('r',I('l','d';)))))}";
//uncomment to print source code before compile
// #define prints
int main(){
   for(int i=0; i<95; i++)
      for(int j=i; j<95; j++){
         std::fstream fs;
         fs.open ("tmptst.cpp",std::fstream::out);
         for(int k=0; k<95; k++)
         if(k<i || k>j){
            fs << S[k];
            #ifdef prints
               std::cout<<S[k];
            #endif
         }
         fs.close();
         #ifdef prints
            std::cout<<'\n';
         #endif
         //Compile and surpress/pipe all output
         //if it doesn't compile we get a nonzero errorlevel (i.e.true) from system.
         if(!system("cl -nologo tmptst.cpp >x"))
            return 0;
      }
      std::cout<<"PRISTINE!";
}

1
我们注意到,尽管这在此编译器上是原始的,但并非在所有编译器上都是如此。
2015年

1
请举一个例子....
莱纳斯

3
在某些编译器上,空的C ++程序生成的程序不执行任何操作。根据iostream的实现,也可以编译#include <iostream>。
2015年

5
@Joshua仅长度为1或更高的子程序很重要,因此与空程序的功能无关。
ThisSuitIsBlackNot

2
@共产国际,不是真的。如果未选中运行可执行文件的框,则该/c选项会自动包含在内,并且会编译(就像创建库而不是程序一样)。如果选中站点不包括的运行框/c,将不会收到成功消息,而是会找到自然的“ LINK:致命错误LNK1561:必须定义入口点”。
莱纳斯(Linus)2015年

32

Python 3、79 33

if 5-open(1,'w').write('world'):a

open(1,'w')打开标准输出,然后我们打印字符串。write返回写入的字符数。这用于加强子字符串的删除:删除字符串的一部分会导致返回5以外的值,并且5减去该值将得出true。但是,这将导致if-body被执行且未a定义。

这是基于安德斯Kaseorg的聪明质朴奎因在这里

由于仅需要验证一条语句,因此它比旧的解决方案要短得多,但也不太通用。

旧解决方案:

try:
 q="print('world');r=None"
 if exec('e=q')==eval(q[17:]):exec(e)
finally:r

验证它确实是一个原始程序:

w=r'''try:
 q="print('world');r=None"
 if exec('e=q')==eval(q[17:]):exec(e)
finally:r'''
exec(w)
for j in range(1,len(w)):
 for i in range(len(w)+1-j):
  e=w[:i]+w[i+j:]
  try:exec(e,{});print('WORKED',e)
  except:pass

一些要点:

  • 每个执行的语句都可以删除。验证q已执行需要在之外的语句q。的try那很好,通过要求至少两个陈述,两者都不可以完全删除求解。
  • q通过最后评估来验证已执行r
  • 验证q没有被修改通过以下步骤实现eval(q[17:]),其中有以评估None用于q将被执行。
  • 这种if情况很难正确解决。为了确保对其进行评估,它具有eset 的良好副作用,需要set r。(这就是我使用Python 3的原因,expr因为该函数确实对表达级副作用产生了奇迹。)

不删除将不会导致语法错误的挑战吗?您似乎挑起了运行时错误。
MartinLütke'15

5
@MartinLütke任何类型的错误都可以。
加尔文的爱好

1
嗯,这不是79个字节吗?
马特

@TheMatt是吗?我只是再次数了数,您似乎是对的。也许我过去数过CRLF换行符...真令人尴尬。谢谢!
菲利普

25

哈斯克尔(61)

x=uncurry(:)
main=putStr$x('w',x('o',x('r',x('l',x('d',[])))))

任何类型的错误都可以吗?在这种情况下:

哈斯克尔(39)

main=putStr$take 5$(++)"world"undefined

如果您删除其中一个字母,这是否有效?
lirtosiast,2015年

在执行期间它将崩溃。因为它将尝试评估未定义。
MartinLütke'15

太好了 懒洋洋的评价FTW,它出现了!
DLosc 2015年

1
我希望'inits'是在前奏:(然后:主要= $ putStr inits “世界” !! 5(27字节)。
马丁Lütke

16

JavaScript,74 73 35字节

if((alert(a="world")?x:a)[4]!="d")x

事实证明答案比我想象的要简单得多。

说明

if(
  (
    alert(a="world") // throws a is not defined if '="world"' is removed
        ?x           // throws x is not defined if 'alert' or '(a="world")' is removed
        :a           // throws a is not defined if 'a="world"' or 'a=' is removed
  )
  [4]!="d"           // if "world" is altered fifth character will not be "d"
                     // if 'd' is removed it will compare "world"[4] ("d") with ""
                     // if '[4]' is removed it will compare "world" with "d"
                     // if '(alert(a="world")?x:a)' is removed it will compare [4] with "d"
                     // if '?x:a' is removed [4] on alert result (undefined[4]) will error
                     // if '[4]!="d"' is removed the if will evaluate "world" (true)
                     // if '!', '!="d"' or '(alert...[4]!=' is removed the if will
                     //     evaluate "d" (true)
)x                   // throws x is not defined if reached

// any other combination of removing substrings results in a syntax error

删除所有内容a="world",但不会出错
anOKsquirrel 2015年

3
@anOKsquirrel只能删除一个子字符串。
丹尼斯

4
我经历过这样的事情:“我可以删除它吗?不,会发生此错误。可以删除吗?嗯,我想这会导致另一个错误。啊哈!那些字符可以被删除!哦,等等...” +1
ETHproductions 2015年

if(a="world")["bol"+a[4]]没有错误。
anOKsquirrel 2015年

4
神圣的牛,现在给人留下了深刻的印象!希望我可以再+1 ...
ETHproductions'Nov

15

Java 8,301字节

因为每个问题都需要Java答案。

class C{static{System.out.print(((((w='w')))));System.out.print((((o='o'))));System.out.print(((r='r')));System.out.print((l='l'));System.out.print(d='d');e=(char)((f=1)/((g=8)-C.class.getDeclaredFields()[h=0].getModifiers()));}public static void main(String[]a){}static final char w,o,r,l,d,e,f,g,h;}

展开式

class C {
    static {
        System.out.print(((((w = 'w')))));
        System.out.print((((o = 'o'))));
        System.out.print(((r = 'r')));
        System.out.print((l = 'l'));
        System.out.print(d = 'd');
        e = (char) ((f = 1) / ((g = 8) - C.class.getDeclaredFields()[h = 0].getModifiers()));
    }

    public static void main(String[] a) { }

    static final char w, o, r, l, d, e, f, g, h;
}

说明

  • public static main(String[]a){} 是必须的。
  • 如果删除了字段声明(或将其声明为非静态的),则第一个静态块将找不到它们。
  • 如果删除了静态块(或将其变为非静态),则不会初始化字段。

最难的部分:

  • 如果final删除了关键字,则第二行的计算结果为1/(8-8),导致/ by zero异常。

为什么不能删除任何打印语句的内部?
Nic Hartley

2
@QPaysTaxes没有空System.out.print()方法。有println(),但没有print()。因此,如果您将其删除d='d',它将The method print(boolean) in the type PrintStream is not applicable for the arguments ()作为错误给出(并且,如果您将其删除d=,则将给出The blank final field d may not have been initialized错误)。
凯文·克鲁伊森

15

功能可按143个 142 136字节

分数通常是UTF-8,因为UTF-16会大2个字节(由于BOM)。

╔══════════╗
║1934282307║╔╗
║5080880373╟╚╝
║80718711  ║
╚══════════╝

因此,一段时间以来,我一直在考虑一个Funciton答案,我认为这是不可能的,因为您总是可以删除整行,并且代码仍会形成有效的块。然后我和Timwi讨论了这个问题,发现您可以将整个数字放在一行中,这样就可以删除它,因为缺少输出连接器会破坏程序。

但是,单行文字非常昂贵,这不仅是因为字符数较大,而且因为非ASCII字符数较多。他提到“空白评论”框让我开始思考...

因此,我想出了一个更有效的解决方案,它使用了一个额外的空注释块,当您尝试删除任何会使文字块保持原样的东西时,该注释块就会中断:

  • 我们可能无法删除第三行,因为那样我们将删除输出连接器。
  • 如果删除第二行,则注释块将失去其顶部边缘并中断。

剩下两个选择(感谢史蒂夫指出):

  • 删除第四行。这使两个盒子都完好无损。但是,当对所得整数19342823075080880373进行解码时,相应的字符串将包含0x18D53B不是有效Unicode字符的代码点,并会System.Char.ConvertFromUtf32崩溃ArgumentOutOfRangeException
  • 从右上角开始删除整行。同样,两个框都保持原样,但结果整数508088037380718711将包含两个无效的代码点0x1B06350x140077,从而导致相同的异常。

请注意,即使没有空白注释块,删除第二行也将导致无效的代码点。但注释块防止我们采取从行的第二线,让喜欢整数193428037380718711,例如,这将不会导致错误。


如果从输出连接器后面的字符开始删除子字符串,然后在1行之后精确地完成子字符串,会发生什么情况?例如,删除注释块的中线和主块中包含“ 80718711”的线,但两个方框的角均保持不变。
史蒂夫

@Steve我已修改答案以解决该问题。在仔细研究了一下之后,这实际上使我节省了两个字符/六个字节。
马丁·恩德

10

红宝石,36岁

eval(*[(s="planet")[$>.write(s)^6]])

我们分配s="planet",然后将该字符串写入STDOUT。这将返回写入的字符数。我们将其与6进行异或运算,以便写入6个字符以外的任何字符,我们将获得一个非零整数。然后,我们s将该索引切成薄片。s“ p”的仅第0个字符是有效的代码字符串(无操作)。我们eval使用(*[argument])等效于该语法的语法将其传递给,只是(argument)它在方法调用之外无效。

通过Ruby 1.9.3和2.2以编程方式验证了原始性


哇靠。这真太了不起了。
2015年

如果您删除该*怎么办?
LegionMammal978 2015年

然后,您将数组传递给eval而不是字符串,这是ArgumentError。
histocrat

9

C#,128个 118 101字节

想滥用连续子字符串规则。

编码

class h{static void Main()=>System.Console.Write(new char[1
#if!i
*5]{'w','o','r','l','d'
#endif
});}

为什么有效

  1. class h并且static void Main()是必需的。
  2. 删除in中的任何char 'w','o','r','l','d'都会导致错误,因为char数组是使用length初始化的1*5
  3. 您不能在不违反连续字符规则的情况下删除Main()中的内容,因为零件之间被前置程序分隔。(见下文)

打高尔夫球和分开之前

class h
{
    static void Main() =>
        System.Console.Write(new char[1 * 5]{'w','o','r','l','d'});
}

验证人

https://ideone.com/wEdB54

编辑:

  • 使用#if !x代替节省了一些字节#if x #else
  • 使用的 =>func语法。#if!x代替#if !x。归功于@JohnBot。
  • 由于使用了=>func语法,因此可以删除多余的preproc条件。

嗨,螺旋!您认为您可以解释答案的方式和原因吗?
isaacg 2015年

@isaacg编辑。证明。
Helix Quar 2015年

我不能让它不跑staticMain
Johnbot

@Johnbot是的。一定是复印错误。固定。
Helix Quar 2015年

您可以通过以下方式来保存字符Main:设置表达式表达式函数成员,并通过在预处理器条件之前删除空格再添加2 个字符class h{static void Main()=>System.Console.Write(new char[1\n#if!l\n*5]{'w','o','r','l','d'\n#if!o\n});\n#endif\n}\n#endif。根据我的计算,这是115。
Johnbot

9

MATLAB,37 36 33字节

feval(@disp,reshape('world',1,5))

由于我不确定是否也可以输出ans =,因此我必须找到一些解决方法以正确的方式输出。单独使用fprintf无效,因为无论我尝试了什么,它都只会拒绝出错。单独使用disp并不是一个选择,因为它只会使用1个参数,并且该参数本身显然也将执行而不会出错。

如果在输出中也包含ans =没问题,那么MATLAB可以使用20个字节来完成:

reshape('world',1,5)

我真的必须了解有关内置函数的更多信息(+1)// //程序得分为20
Abr001am 2015年

2
这实际上取决于规则的严格程度。他们声明应打印“ world”(+可选的尾随换行符),因此为33字节。
slvrbld 2015年

是的,我们将其计为33。感谢您的理解:)
卡尔文的爱好

9

> <>,17个字节

e"ooooo7-c0pBhtra

在线尝试!

打印“地球”。

><>程序无错误退出的唯一方法是执行;字符,这是一个问题,因为您可以删除之前的所有字符,因此这;是第一个执行的字符。您可以通过使用p命令修改程序以使其;在执行期间包括在内来解决该问题。删除代码的任何部分都将导致;永远不会通过无效指令Bht,堆栈下溢以及无限循环而产生错误,从而最终导致内存不足。我只需要确保所有无限循环不断填满堆栈即可。

使用此python代码段测试了所有变体:

code = 'e"ooooo7-c0pBhtra'
count = {"invalid":0, "underflow":0, "memory":0}
for l in range(1, len(code)):
    for x in range(0, len(code)-l+1):
        print(code[:x] + code[x+l:], "\t\t", end='')
        try:
            interp = Interpreter(code[:x]+code[x+l:])
            for _ in range(0,1000):
                interp.move()
            print(len(interp._stack), "< ", end='')
            interp2 = Interpreter(code[:x]+code[x+l:])
            for _ in range(0,2000):
                interp2.move()
            print(len(interp2._stack))
            count["memory"] += 1
        except Exception as e:
            print(e)
            if str(e) == "pop from empty list": count["underflow"] += 1
            else: count["invalid"] += 1
print(count) 
#don't judge me

由> <>的创建者添加到正式的fish.py解释器中(稍作修改)。在152个可能的子程序中,有92个由于无效指令而出错,18个由于堆栈下溢而导致,42个因内存不足而出错。

有趣的事实是,它的第一个版本e"ooooo6-c0pAhtra有几个怪胎子程序,这些子程序设法使用put命令放置a [来清除堆栈,以代替无效指令A。另外,“地球”是唯一可使用此方法的短语,因为第一个字母e是中的有效指令><>。否则,该"命令必须放在程序的最前面,并且有效的子程序"本身就可以。


8

红宝石,34岁

eval(*[($>.write("world")-1).chr])

它包含一些组件:

eval(*[ expr ])是从histocrat的答案中借来,它是原始的,并且要验证expr的返回值是一个没有错误的有效红宝石程序。method(*arr)是一个Ruby语法,它method使用arr作为参数的值进行调用。这里需要这样做的原因是因为它作为方法的参数有效,因此,如果eval将其删除,(*[expr])则是语法错误。如果将expr删除,则会eval抱怨没有足够的参数

$>.write("world")-1除了字符串内部和减法之外,无法进行整形。$>.write("world")将“ world”写入STDOUT并返回写入的字符数,然后减去1。因此,如果程序未破坏,则值将恰好为4。如果它被重整(-1除去或缩短字符串),则它将返回-1,0、1、2、3或5之一。任何其他处理都会导致语法错误。

呼叫chr数字将返回该数字表示的字符。因此,在上述示例的结果上调用时,它在-1上出错,否则返回一个单字符字符串。

我实际上不确定为什么会这样,但是ruby似乎解释\x04为空格字符,这意味着该表达式有效(空ruby程序什么也不做)。但是,其他任何字符(\x00- \x03\x05)都会导致Invalid char '\x01' in expression。我通过简单地遍历可能对返回数字进行的数学运算来发现此问题。以前我用过

$>.write("planet
")*16

其中,“ planet”加上换行符是7个字符,乘以16会得到112 p,这是默认情况下定义的ruby中唯一的单字母函数。如果不提供任何参数,则实际上是无操作


值得一提的$><<"%c"*5%%w(w o r l d)是:非常接近但并非原始。删除"%c"*5%不会导致任何错误。迷你说明:

$>是stdout,<<是在其上调用的函数。"%c"*5生成格式字符串"%c%c%c%c%c",然后尝试%通过数组进行格式化():%w(w o r l d)这是的较短版本['w','o','r','l','d']。如果数组中的元素太少或太多,以致与格式字符串不匹配,则会抛出错误。阿基里斯的致命弱点是"%c"*5,并且%w(w o r l d)都可以独立存在,并且$><<只需要其中一个参数即可。因此,有几种不同的方法可以将此程序整合为无错误的表亲。


使用此验证:

s = 'eval(*[($>.write("world")-1).chr])'
puts s.size
(1...s.length).each do |len| #how much to remove
  (0...len).each do |i| #where to remove from
    to_test = s.dup
    to_test.slice!(i,len)
    begin #Feels so backwards; I want it to error and I'm sad when it works.
      eval(to_test)
      puts to_test
      puts "WORKED :("
      exit
    rescue SyntaxError
      #Have to have a separate rescue since syntax errors
      #are not in the same category as most other errors
      #in ruby, and so are not caught by default with 
      #a plain rescue
    rescue
      #this is good
    end
  end
end

按照历史学家的回答进行解释会很好。似乎您使用的是相同的基本方法,但是由于我不了解Ruby,所以无法理解细节。
ThisSuitIsBlackNot 2015年

@ThisSuitIsBlackNot尽我所能,您不了解的内容吗?
Shelvacu 2015年

很好的解释,谢谢!
ThisSuitIsBlackNot

6

Python 3,43个字节

for[]in{5:[]}[open(1,"w").write("world")]:a

在线尝试!

这个怎么运作

为了防止子字符串被删除,我们使用open(1,"w").write代替print。在Python 3中,write返回书面字符数,我们将验证该字符数5以确保没有删除字符串的任何部分。为此,我们在字典中查找返回值{5:[]},然后使用循环遍历结果for[]in…:a,如果没有得到一个空的Iterable或for删除了该语句,这将失败。


4

Javascript(Node.js),93 95字节

if(l=arguments.callee.toString().length,l!=158)throw l;console.log("world");if(g=l!=158)throw g

两次检查自己的大小,因此如果缺少任何字符,则会引发错误。长度为156,因为Node.js function (exports, require, module, __filename, __dirname) {在运行时添加了代码。

感谢MartinBüttner指出错误。立即修复。


4

Perl 5.10 +,71 63字节

(${open 0;@{\(read(0,$a,63)!=63?die:@_)};say"world"});{$a//die}

world用尾随换行符打印。像这样运行:

perl -M5.010 file

这取决于源代码的字节数,因此file必须包含上面的代码,而不能包含其他任何内容(无shebang,无尾随换行符)。Perl 5.10+是必需的,say并且是define -or运算符//


用Perl编写原始程序非常困难,因为:

  • 任何裸字标识(例如fooa_)是一个有效的语句no strict 'subs';(默认值)。这意味着程序不能以字母,数字或下划线开头或结尾。

  • 正如tchrist解释的那样,“通过符号解引用指定的标识符对其名称绝对没有任何限制。” 这意味着该计划不能与任何印记的开始$@%,或者*,因为删除所有,但第一和最后一个字符总是会留下一个有效的变量名。

  • $_默认情况下,许多内置函数(包括大多数能够产生输出的函数)都可以使用,因此即使您删除了参数(例如say"world"vs. say),调用也通常会起作用。

这个怎么运作

该解决方案的灵感来自Naouak的Node.js答案,该答案将检查其自身的长度以确保未删除字符。

该程序有两个部分,一个部分在括号内,另一部分在一个块内:

(...);{...}

第一部分读取源文件,如果长度少于63个字符,则会死掉。第二部分检查read执行是否成功。如果删除了任一部分(带或不带括号或花括号),则另一部分将引发异常。

删除程序的中间或左侧或右侧将使括号和/或花括号不平衡,从而导致语法错误。

如果第一die被改变(到dedide,或ie,它们都是有效的标识符),则长度检查变为:

@{\(read(0,$a,63)!=63?di:@_)};

结果为:

@{\'di'};

这需要对字符串的引用,然后尝试将其作为数组取消引用,从而产生错误:

Not an ARRAY reference

如果更改了其他任何语句,则长度检查将失败并且程序将终止。


通过以下程序验证原始数据:

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;

use File::Temp;
use List::MoreUtils qw(uniq);

sub delete_substr {
    my ($str, $offset, $len) = @_;

    my $tmp = $str;
    substr($tmp, $offset, $len) = '';

    return $tmp;
}

sub generate_subprograms {
    my ($source) = @_;

    my $tot_len = length $source;
    my @subprograms;                                             

    foreach my $len (1 .. $tot_len - 1) { 
        foreach my $offset (0 .. $tot_len - $len) {
            push @subprograms, delete_substr($source, $offset, $len);
        }                                                        
    }                                                            

    return uniq @subprograms;                                    
}                                                                

chomp(my $source = <DATA>);                                                                                                       
my $temp = File::Temp->new;                                                                                        

foreach my $subprogram ( generate_subprograms($source) ) {       
    print $temp $subprogram;

    my $ret = system(qq{/usr/bin/perl -M5.010 $temp > /dev/null 2>&1});
    say($subprogram), last if $ret == 0;

    truncate $temp, 0;
    seek $temp, 0, 0;
}

__DATA__
(${open 0;@{\(read(0,$a,63)!=63?die:@_)};say"world"});{$a//die}

4

Ruby + coreutils,33 27 26字节

`base#{$>.write"world
"}4`

在线尝试!

ruby中的反引号在其中执行命令,并以字符串形式返回放入STDOUT的程序。该#{expr}语法允许将表达式嵌入字符串和反引号中。该程序可以重写(非原始方式)为:

system("base" + (STDOUT.write("world\n")).to_s + "4")

IO#write返回写入的字节数,因此,如果字符串缩短,那么它将不是正确的数字。#{}自动嵌入会使数字成为字符串。如果删除了某些片段,并且没有导致语法错误,则将运行错误的命令。如果"world"删除的一部分,则将尝试base04通过之一base54运行。

换行符是必需的,无论是在字符串内还是在字符串外。否则,`base可以删除前5个字符(),使整行成为注释。此外,在第一个反引号和之间必须有一个或多个字符#,否则{可以将其删除以使整个内容成为shell注释。


exec(*[(s="ec%co earth")%s[10]])

exec用指定的命令替换当前的ruby进程。有关语法及其必要性的说明,请参见我的其他答案meth(*[])

(s="ec%co earth")将字符串“ ec%co earth”分配给变量s。分配返回分配的内容,因此也返回字符串。

"format string %d" % 5是的语法糖sprintf("format string %d",5),但是%不需要空格。

s[10]在索引10处获取字符串中的字符。取消组合时,此字符为“ h”,即字符串中的最后一个字母。但是,删除字符串中的任何字符都意味着字符串较短,因此索引10处没有字符,因此s[10]返回nil"%c" % nil导致错误。

如果%s[10]被删除,ruby尝试运行ec%co earth不起作用的命令。

更改1010还会导致未知命令(eceoecco)。从技术上讲,完全删除它不是语法错误,因为它会#[]在字符串上调用方法,但随后会抱怨参数不足。


通常,有关解决此问题的注释:必须有一些包装程序,该包装程序必须以原始的方式抽象地验证内部代码。例如,在末尾(blablabla/somevar)处有除法的程序将永远无法工作,因为可以始终删除除法(blablabla)。这些是我到目前为止使用过的一些包装器:

  • eval(*[])历史学家在我的第一个答案中使用的代码。验证输出是否为有效的ruby程序
  • exec(*[])上面使用的代码,验证响应是否为有效命令
  • `#{}`

反引号语法也运行命令(并因此验证它是有效的命令),但是STDOUT被捕获为字符串,而不是作为父进程的(Ruby的)STDOUT输出。由于这个原因,我无法将其用于此答案,编辑:我使它起作用。上面概述的局限性。

编辑:感谢@histocrat指出了一些缺陷


很酷的方法!您可以(因此必须)删除write字符串之间和字符串开头的空格,但是我认为这不会影响原始性。另外,在我的机器上,base64挂起等待输入,这可能违反了规则。
历史学家

@histocrat哇,我很惊讶$>.write"world",谢谢!至于等待输入的base64,它似乎因系统而异。TIO工作正常。这使得它是否遵循规则变得更加模糊。
Shelvacu

3

PowerShell,(97字节+ 5表示程序名称)= 102字节

"$(try{if(($a=(gc .\c.ps1).Length)-eq97){"world";a}}catch{if($a-ne97){a}$error.clear();exit}a)";a

在破坏之前对其进行检查……两次。

期望另存为c.ps1并从本地目录执行,如下所示:
PS C:\Tools\Scripts\Golfing\> .\c.ps1

别名gc的缩写,Get-Content类似于cat读取文件(在这种情况下,是我们的执行路径.\c.ps1)。我们获取.Length文件的,将其设置为$a,然后使用来检查它是否等于97 -eq97。如果相等(即程序尚未修改),则使用打印"world"并执行无效命令a。这迫使catch生效,这使我们能够再次检查自己。这次,如果我们的代码不等于97,则抛出一个无效命令,因此我们的程序有错误,并将错误文本打印到输出中。然后我们clear()出现错误并且exit正常。

显然,如果其中一个if语句被篡改,则另一个将出错。如果的任何部分"world";被篡改,则第一部分if将导致错误。由于它必须是连续的,因此我们不能删除这两个if语句。中间的字符串将导致括号不匹配,或导致第二个字符串{a}被执行。的try/ catch是从第一捕获错误if的语句,所以我们适时地清除它。外部"$( )"防止琴弦的任何一端被夹住。最后;a是防止中间部分被剥夺,这将导致有效程序(例如,"it}a)";a先打印it}a)后出错)。

有几种特殊情况:

  • 如果gcgc<space>或者gc .\被删除,该方案最终将报错了因内存不足错误的一番韵味(由于反复自执行调用),并有可能崩溃的外壳(可能的计算机)。未经测试。
  • 如果将<space>.\c.ps1.\c.ps1删除,程序将停止并提示用户输入。不管用户输入什么,程序都会出错,因为大小计数将是错误的。
  • 如果某个子字符串从s开始$并在最后一个"字符之前终止,则该程序将输出任何剩余的内容,然后由于a无效而出错。

经过以下验证:

$x='"$(try{if(($a=(gc .\c.ps1).Length)-eq97){"world";a}}catch{if($a-ne97){a}$error.clear();exit}a)";a'
$yy='"$(try{if(($a=( .\c.ps1).Length)-eq97){"world";a}}catch{if($a-ne97){a}$error.clear();exit}a)";a'
$yyy='"$(try{if(($a=(.\c.ps1).Length)-eq97){"world";a}}catch{if($a-ne97){a}$error.clear();exit}a)";a'
$yyyy='"$(try{if(($a=(c.ps1).Length)-eq97){"world";a}}catch{if($a-ne97){a}$error.clear();exit}a)";a'

for($i=1;$i-lt$x.Length;$i++){
  for($j=0;$j-lt($x.Length-$i);$j++){
    $y=($x[0..$j]+$x[($i+$j+1)..$x.Length])-join''
    $y>.\c.ps1
    $error.clear()
    if(!($y-in($yy,$yyy,$yyyy))){try{.\c.ps1}catch{};if(!($error)){exit}}
    $q++;
    write-host -n "."
    if(!($q%150)){""}
  }
}
"No success."

(感谢马丁的广泛协助!)


3

C(gcc)(Linux,-Werror=undef),66字节

main(a){a
=
1
/
(puts("world")/
6);
#if(7^__LINE__)
#else
}
#endif

在线尝试!

巨大的挑战!这看似很难,但是我敢肯定我现在有一个有效的程序!

使用预处理程序命令,因此不能删除任何换行符,因为main仅在包含右括号__LINE__==6。这也使您无法完全清除main,因为那样会导致#endif浮动(因此,#endif在之外很重要main)。

我用的#else,因为我已经变得相当确信没有任何版本的__LINE__==6不能有一个子删除,仍然是真实的,因为两个6__LINE__自己是truthy。它还使用-Werror=undef,这样类似的东西#ifdef(LINE__)不会求值为假,而是一个错误。

使用gcc(至少在Linux上),puts将返回打印的字符数(包括结尾的换行符),因此删除字符串的任何部分均会导致puts("...")/6return 0,从而1/0导致浮点异常。请注意,除非1/0将异常分配给某些东西,否则不会引起此异常,因此a=必须为。

如果没有创建错误(通常是语法错误或链接错误),则无法删除任何行的其他部分。

另外,这为C ++提供了一个86字节的解决方案,只需添加#include <cstdio>并声明a为即可int在线尝试!(C ++)


除非我弄错了,否则您可以1/在离开换行符的同时删除它仍然会运行
gastropner

@gastropner对了。1我相信应该在上一行。
克里斯(Chris)

可悲的是,同样的事情仍然存在。然后可以删除=1。我认为您需要自己将1放在一行上。
gastropner '18

@gastropner我认为你是对的。我稍后再看。谢谢!
克里斯(Chris)

2

PHP,73字节

<?=call_user_func(($p='ns')|(($f="u{$p}erialize"))?$f:'','s:5:"world"');

解释

我假设默认的php.ini配置。因此short_tags被禁用。这意味着您不能=从开始标签中删除。

这基本上是<?=unserialize('s:5:"world"');

如果您删除序列化字符串的任何部分,则会收到错误消息。

您只需删除即可unserialize,脚本将仅输出序列化的字符串。为了克服这个问题,我使用call_user_func。删除参数之一将导致错误。

'<?=call_user_func('unserialize','s:5:"world"');

但是,您可以删除un,以调用该serialize函数。因此,我们取出“ ns”。删除任何字符都不会导致错误的函数名称。

<?=call_user_func(($p='ns')&&($f="u{$p}erialize")?$f:'','s:5:"world"');

如果要将变量赋值与输出标签一起使用,我们将使用内联。而不是&&使用“ |” 防止删除单个&或删除$f分配

您可以删除='ns')&&($f="u{$p}erialize"并最终得到($p)?$f:''。因此,我在周围加上了额外的括号$f="u{$p}erialize"

注意

从技术上讲,您可以删除开头的标签而不会产生错误。但是,这不再是PHP脚本,而只是纯文本文件。


2
关于您的上一个注释,纯文本文件仍然是有效的PHP程序,对吗?所以我不确定这是否有效。
加尔文的爱好2015年

它不再是PHP,而是纯文本/ html,因此不再是有效的PHP程序
Martijn 2015年

1

Matlab的(77)

bsxfun(@(c,b)arrayfun(@(x)getfield(c,{x}),conv(b,ismember(4,b))),'world',1:5)

试试吧

注意:

遵循@Optimiser设计CPR之类的建议后,我遇到了无法预料的子字符串,该子字符串在删除时不会导致任何编译错误,例如:arrayfun(@(x)a(x),prod(b,ismember(4,1:5))),从此先前的编辑中删除 feval(@(a)arrayfun(@(x)a(x),prod(b,ismember(4,1:5))),'world')不会产生任何错误!同样,对于最近的同一版本,还有bsxfun(@(a,b)arrayfun(@(x)(x),prod(b,ismember(4,b))),'world',1:5)bsxfun(@(a,b)a,'world',1:5),如果您问我在输出控制台中找到它们时我怎么样了,我哭得像个婴儿,所以下面是程序:

b=0;string='bsxfun(@(c,b)arrayfun(@(x)getfield(c,{x}),conv(b,ismember(4,b))),''world'',1:5)'
for u=1:numel(string),for j=u:numel(string)-2,try a=eval([string(1:u) string(j+2:end)]);catch(b); a=0;end; if a~=0, ['here is it : ' string(1:u) string(j+2:end)],end;end;end

非原始程序的示例

编辑:

感谢@Martin旁边的每个人都指出了我之前的代码(非错误)。


1

SmileBASIC,63个字节

REPEAT
A=1/(PRGSIZE(0,1)==63)?"world
UNTIL 1/(PRGSIZE(0,1)==63)

1

梨树,17字节

该程序包含设置了高位的字节(这不是有效的UTF-8,因此无法发布到TIO上),因此这是一个xxd可逆的十六进制转储:

00000000: 7072 696e 7427 776f 726c 6427 23cd 4290  print'world'#.B.
00000010: bf                                       .

说明

这只是print'world'附加了校验和。我已经通过蛮力验证,所有可能的删除都不会给程序提供有效的校验和,因此,在任何可能的删除之后都会出现错误。

相当无聊,但与现任领导人保持联系,所以我觉得值得一提。

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.