在Java中以比字符串内容更少的字符打印字符串

3
这是一项额外学分作业,下个学期就要开始了。我需要将一个段落打印到屏幕上,但代码中的字符数量必须少于段落中的字符数量。以下是该段落:
“我保证我的名字出现在其中的每个程序都是由我(和我的共同作者,如果有的话)编写的,并且我完全理解这个程序。除非另有说明,否则我提交的每个程序都将完全是我自己的工作。我知道学术不诚实不仅包括复制他人的作品,而且还包括教唆或促进复制。与任何其他提交过去或现在的提交相似的代码将无论解释如何都不得分。我知道学术不诚实的后果是班级的“F”等级。我保证通过编写自己的程序来致力于学习Java。我将努力注意细节并编写程序以便我自己和其他程序员可以理解。”
程序不能接受任何输入...没有文件、下载等。
我的初步想法是,由于没有人能够做到,所以它肯定超出了我们目前在课堂上学到的范围。既然要少,你显然不能只是像每个人在任务的第一部分(常规学分)中所做的那样逐行println该段落。
我研究了使用java.util.zip进行字符串压缩,但我一直遇到的问题是不允许任何输入。我现在搁置的一个想法是:是否有一种方法可以将字符串编码为压缩形式,使代码比段落的未压缩版本少字符,并且在将其打印到控制台时只需解压缩字符串?
我也尝试过ASCII值,然而,ASCII值仅表示字符,而且所有ASCII值的字符长度都比它们用于表示的字符长,所以我没有看到它们的用处。
我现在想到的想法是取最长的重复单词并给它们分配一个字符串变量名。然后,只需使用变量串联样式将段落中的单词替换为变量即可。这是我的代码:
import static java.lang.System.out;

public class Pledge {
  public static void main(String[] args){
    String s=" understand ",p=" program",z=" academic dishonesty ",c=" copying",i="I pledge ";
    out.println(i+"that every"+p+" with my name on it shall be written by me (and my co-authors, if any) and that i fully"+s+"the"+p+". Every"+p+" I submit shall be entirely my own work unless otherwise attributed. I"+s+"that"+z+"not only includes"+c+" other people's work, but also abetting or facilitating"+c+". Code that is similar to any other submission past");
    out.println("or present will get no credit whatever the explanation. I"+s+"that the consequence of"+z+"is a grade of 'F' for the class."+i+"to devote my efforts to learning Java by writing my own"+p+"s. I shall strive to be attentive to detail and write"+p+"s "+s+"able by myself and other"+p+"mers.");
  }
}

附上的代码有762个可打印字符。由于我还差112个字符,而且代码已经看起来很糟糕,有两个巨大的println语句,我觉得我可能走错了方向。我不希望有人为我编写代码(我讨厌这样做),但是一些提示或推荐将极大地受到赞赏。谢谢!

4
你仍需要在源文件中包含“zip”文件的内容。 承诺书,经过bzip压缩和base64编码后长度为580字符。 这样你只剩下210个字符用于解压缩、解码和打印,可能会有些吃力。 (特别是因为没有简单的方法来解压缩字节数组。) - millimoose
字符可以相当大。如果您使用Unicode可打印部分编码数据,则可以存储大量位。代码看起来像(而且可能包含)中文,但是嘿 :) - Maarten Bodewes
1
@MikeSamuel 令人震惊的是,在打了很多高尔夫球之后,“zip”解决方案缩减到了750个字符。我已经将它放在ideone上:http://ideone.com/r920A7。(对于OP:除非你想要一个剧透,否则不要点击该链接。你很难在提交时解释它的工作原理,所以最好自己尝试实现这种方法——现在你至少知道这种方法是可行的。) - millimoose
1
@millimoose,“Input”是你接受的内容。“Conanput”是你从被杀敌人的尸体堆中夺取的内容。Conan不会遵守作业规则,他会将它们打破得无人记得它们曾经存在过。“我发誓要让每一个Java程序在听到我的名字时都颤抖不已。” - Mike Samuel
1
我认为你们学校关注的方向不对。 - Isaac
显示剩余18条评论
3个回答

2
你可能想要研究的一件事是Huffman编码。这种方法与你发布的程序类似,但在压缩段落的方式上更加彻底。因此,你可以在压缩文本(预先)之后,将压缩版本放入源文件中,然后解压并打印。
此外,还有一些小技巧可以节省一些字符,例如:
  • main(String[] args) 可以改为 main(String[]v)(节省4个字符)
  • 你可以使用比“Pledge”更短的名称,也许是一个单字符名称(节省5个字符)
  • 你可以将所有内容放在一行上(节省很多字符)
它们虽然很小,但会累积起来。

一行代码的程序确实可以节省很多字符。 - Jonathan Drapeau

1
一个创意的解决方案可能是使用Unicode编写程序,并使用UTF-16编码字符串。这样可以使用一半的“可打印字符”存储字符串。例如:
public static void main(String[] args) throws Exception {
    String s = "䤠灬敤来⁴桡琠敶敲礠灲潧牡洠";
    System.out.println(new String(s.getBytes("UTF-16BE"),"UTF-8"));
}

打印我保证每个程序。输出为28个字符,但用于存储字符串的“可打印字符”数量仅为14个。要编码793个可打印字符,您需要397个字符来存储该字符串,留下258个字符用于实际代码。


那么我会使用该语言在字符串s中编写整个承诺,然后getbytes()告诉编译器以哪种字符集打印它? - user1843232
1
@user1843232 不,意思是将两个ASCII字符映射到一个UTF-16字符上。诀窍在于UTF-16字符仍然占用两个字节 - 它依赖于能够争论“字符”与“字节”的语义。 - millimoose
@KevinK:除非我的往返代码有问题,否则由于某种原因这不起作用:http://ideone.com/KapoXg。往返的结果几乎与原始结果相同,但仍可能需要调整一些东西才能使其正确。 - millimoose
@millimoose 说实话,我很惊讶它映射到可打印字符。我确实测试了整个段落,但由于这是作业,所以没有包含在我的答案中。 - Kevin K
考虑到誓言的威胁性质,我相信 OP 不会提交一个难以理解且需要大量无意义汉字和表意符号以及对输出数据进行任意调整而无法自信地解释其工作原理的复制/粘贴解决方案。 - millimoose
显示剩余7条评论

0

你目前的方法可以进行改进,使用printf()及其显式参数索引功能。这样可以为原始字符串中的每个出现节省1个字符(从而让您“压缩”更短的子字符串)。它还可以消除字符串变量声明,每个子字符串少三个字符。

这里是 ideone 的版本:http://ideone.com/lnrTrG - 我设法将其缩减到 784 个字符,而不必使用任何过于聪明的东西。也有可能我提取的子字符串选择不够优化。

我尝试使用{{link1:MessageFormat.format()}}来实现相同的效果,但它无法替换所有占位符。考虑到printf()版本接近极限,可能无法压缩更短的子字符串(因为MessageFormat的显式索引占位符比printf()的少一个字符),甚至无法抵消java.text.MessageFormat.format()的额外32个字符的开销。(话虽如此,这也值得一试。仅占位符就可以节省29个字符,所以很接近。)


你的问题还有另一个直接的答案:

是否有一种方法可以以压缩形式编写字符串,使代码比段落的未压缩版本更少,并在将其打印到控制台时简单地解压缩字符串?

你已经找到了 java.util.zip ,谜题缺失的部分是 base-64编码。这将让你把压缩后的字节存储在由可打印字符组成的 String 中。它会占用比编码数组长度更多的字符,但(幸运的是)远比原始字符串少。(它还应该比直接编写字节数组值更短。)您可以使用 DatatypeConverter 的实用程序方法来处理此编码。(感谢 @owlstead 提供提示。)

我的同事提出了一种比 base-64 更好的方法,那就是使用类似 Latin-1 的旧字符集对压缩数据进行编码。由于大多数 Latin-1 字符都是可打印的,所以可以在 Java 字符串字面量中使用一个字符来写入它们。需要转义的那几个字符仍然比 base-64 更简洁。如果您的源文件也可以使用 Latin-1 编码,则还可以避免争论字符和字节之间的区别。

另一个微小的优化让我在高尔夫时达到了772个字符:http://ideone.com/xSaTFs - millimoose
1
http://download.oracle.com/javase/6/docs/api/javax/xml/bind/DatatypeConverter.html - Maarten Bodewes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接