简体   繁体   中英

Printing a string in Java using less characters than the contents of the string

This is for an extra credit assignment in school that will be coming up next semester. I have to print a paragraph to the screen but the amount of characters is the code must be less than the amount of characters in the paragraph. The paragraph is below:

"I pledge that every program with my name on it shall be written by me (and my co-authors, if any) and that I fully understand the program. Every program I submit shall be entirely my own work unless otherwise attributed. I understand that academic dishonesty not only includes copying other people's work, but also abetting or facilitating copying. Code that is similar to any other submission past or present will get no credit whatever the explanation. I understand that the consequence of academic dishonesty is a grade of 'F' for the class. I pledge to devote my efforts to learning Java by writing my own programs. I shall strive to be attentive to detail and write programs understandable by myself and other programmers."

The total number of characters in the program should be fewer that the total number of characters in the pledge (655 printable, 793 total).

The program can take no input whatsoever...no files, downloading, etc.

My initial thought was that since no one has ever been able to do it, it must be outside the scope of what we've learned in class so far. Since it has to be less, you obviously can't just println the paragraph line by line which is what everyone does in the first part (regular credit) of the assignment.

I have researched string compression using java.util.zip but I keep running into the problem that no input is allowed. An idea that I've back shelved for now is: Is there a way to code the strings in compressed form, making the code less characters than the uncompressed version of the paragraph, and simply uncompress the string as I print it to the console?

I've also dabbled with ASCII values, however, the ASCII values represent characters only AND all ASCII values have longer character length than the character they would be used to represent so I didn't see the use for that.

The idea that I have settled on for now is to take the longest repeated words and assign them a string variable name. Then, simply substitute the words in the paragraph with the variable concatenation style. This is my code so far:

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.");
  }
}

The attached code is 762 printable characters. Since I am 112 characters off and the code already looks terrible with two giant println statements, I kind of feel like I am not on the right track. I don't expect any code to be written for me (I hate that), but a few hints or tips to push me in the right direction would be greatly appreciated. Thanks!

One thing you might want to look into is Huffman encoding . The approach is similar to that in the program you posted, but much more thorough in terms of how it compresses the paragraph. So you could compress the text (beforehand), place the compressed version in your source file, uncompress and print.

Also there are little tricks here and there that can shave off a few characters as well; for example,

  • main(String[] args) could be main(String[]v) (4 chars saved)
  • You can use a name shorter than Pledge , maybe a single-character name (5 chars saved)
  • You can put everything on one line (many chars saved)

They're little things but they'll add up.

A creative solution might be to write your program in Unicode and encoding the string using UTF-16. This allows you to store the string using half the number of 'printable characters'. For example:

public static void main(String[] args) throws Exception {
    String s = "䤠灬敤来⁴桡琠敶敲礠灲潧牡洠";
    System.out.println(new String(s.getBytes("UTF-16BE"),"UTF-8"));
}

prints I pledge that every program . The output is 28 characters, but the number of 'printable characters' used to store the string is only 14. With 793 printable characters to encode, you'd need 397 characters for the string, leaving you with 258 to work with for actual code.

A refinement of your current approach is using printf() and its explicit argument indexing feature. This will both save you 1 character for every occurence in the original string (thus letting you "compress" shorter substrings. It also gets rid of the string variable declaration, which is three fewer characters per substring and a bit.

The spoilerrific ideone version is here: http://ideone.com/lnrTrG – I managed to get it down to 784 characters, without having to use anything exceedingly clever. It's also possible that my choice of extracted substrings wasn't optimal.

I tried achieving the same using MessageFormat.format() , but it wouldn't replace all the placeholders. Considering how close to the limit the printf() version is, it's possible that the ability to compress shorter substrings (because MessageFormat 's explicit-index placeholders are one character shorter than printf() 's) wouldn't even offset the extra 32 characters of overhead from java.text.MessageFormat.format() . (That said, it might be worth a try. You save 29 characters on the placeholders alone so it's close.)


There's also a direct answer to another point in your question:

Is there a way to code the strings in compressed form, making the code less characters than the uncompressed version of the paragraph, and simply uncompress the string as I print it to the console?

You've already found java.util.zip , the missing piece of the puzzle is base-64 encoding . This will let you store the compressed bytes in a String consisting of printable characters. It will take up more characters than the length of the encoded array, but (luckily) far fewer than the original string. (It should also be shorter than writing out the byte array values directly.) You can use the utility methods of DatatypeConverter to work with this encoding. (Thanks to @owlstead for the tip.)

An even better method proposed by my coworker that's even better than base-64 is simply encoding the zipped data using a legacy character set like Latin-1. Since most Latin-1 characters are printable, they can be written in a Java string literal using one character. The few that will need escaping will still be less bloat than base-64. If your source file can also be encoded in Latin-1, this will also avoid having to argue the difference between characters and bytes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM