2

I am writing a program that has to decode QR Codes. The codes are internally represented as a 2D Boolean List. The codes will usually be read as text files containing 1s and 0s, where 1 means a dark module (true) in the matrix, and 0 a light module (false).

I have to implement a method, which will take an InputStream and then has to return a QR Code back. I'll have to read .txt which contains 1s, 0s and comment lines beginning with '#'. I need to make the method ignore those comment lines, but I am not sure how to do it.

Here are some relevant parts of the code:

First the QR Code constructor (All of the methods used in the constructor work and do their job):

public class QRCode {

private List<List<Boolean>> data; //A 2D Boolean matrix, true means black, false means white.

public QRCode(List<List<Boolean>> data)
{
    if (data == null)
        throw new NullPointerException();
    if (QRCode.isQuadratic(data) == false)
        throw new InvalidQRCodeException("Matrix must be quadratic!");
    if (QRCode.versionCheck(data) < 1 || QRCode.versionCheck(data) > 40)
        throw new InvalidQRCodeException("Invalid Dimensions (Version).");
    if (QRCode.correctlyAlligned(data) != true)
        throw new InvalidQRCodeException("Improper Allignment!");
    if (QRCode.correctTimers(data) != true)
        throw new InvalidQRCodeException("Incorrect Timing Pattern!");
    if (QRCode.correctFormatting(data) != true)
        throw new InvalidQRCodeException("Incorrect Formatting!"); 

    this.data = data; 
}   

}

This is the method I'm referring to. What I wrote sofar at least. Also, if the .txt file contains anything other than 1s, 0s and comment, it should throw an exception. PS: I've never used InputStreams before, I tried googling this but all answers I found were for specific types of Streams, and they use a .readLine() method, which my IS here is not letting me use.

public static QRCode fromFile(InputStream is) throws IOException 
{   
    int i;
    List<List<Boolean>> data = new ArrayList<>(); //a 2D Boolean Matrix
    int y = -1, x = -1;

    if (is == null)
        throw new NullPointerException();
    while((i = is.read())!=-1) //Reading begin
    {
        if (i == (byte) '\n') //If a line in .txt file ends.
        {
            y++; 
            data.add(new ArrayList<Boolean>());
            x = 0;
        }

        if ((char) i == '1') //|| (char) i == '0')
        {
            data.get(y).add(true);
            x++;
        }
        if ((char) i == '0') //||
        {
            data.get(y).add(false);
            x++;
        }
    }


    return new QRCode(data);
}

An example of text files that I'd be handling:

# name: small
# type: bool matrix
# rows: 25
# columns: 25
1 1 1 1 1 1 1 0 1 1 1 1 0 1 1 0 1 0 1 1 1 1 1 1 1
1 0 0 0 0 0 1 0 0 0 0 1 1 1 1 0 0 0 1 0 0 0 0 0 1
1 0 1 1 1 0 1 0 0 1 0 1 0 1 0 1 0 0 1 0 1 1 1 0 1
1 0 1 1 1 0 1 0 0 0 1 1 0 1 0 0 0 0 1 0 1 1 1 0 1
1 0 1 1 1 0 1 0 0 0 1 1 1 0 0 0 1 0 1 0 1 1 1 0 1
1 0 0 0 0 0 1 0 0 1 0 1 0 0 1 0 0 0 1 0 0 0 0 0 1
1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0 1 1 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0
1 1 0 1 1 0 1 0 0 1 0 0 1 0 1 1 0 0 1 0 0 0 0 0 1
1 1 1 1 0 0 0 0 1 0 1 0 0 1 1 1 0 0 0 1 1 1 0 0 0
1 0 0 1 1 1 1 0 1 1 0 0 1 1 0 1 1 0 1 1 1 0 1 0 1
0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 1 0 1 0 1 1 1 1 0
0 1 1 0 0 1 1 1 0 1 1 0 0 0 0 0 1 0 1 1 0 1 0 1 1
1 1 0 0 0 1 0 0 0 0 1 0 1 0 1 1 1 1 0 0 1 1 0 1 0
1 1 1 0 0 0 1 1 0 1 0 0 0 1 1 1 1 0 1 0 0 0 0 1 1
1 0 1 1 0 1 0 0 0 0 1 0 1 0 1 0 1 0 0 1 0 1 1 0 1
1 0 1 1 0 1 1 1 1 0 0 1 1 1 0 1 1 1 1 1 1 0 1 1 1
0 0 0 0 0 0 0 0 1 0 1 1 0 1 0 0 1 0 0 0 1 0 1 0 1
1 1 1 1 1 1 1 0 0 1 1 0 1 1 0 0 1 0 1 0 1 1 0 0 1
1 0 0 0 0 0 1 0 0 0 1 1 0 1 1 0 1 0 0 0 1 1 0 0 0
1 0 1 1 1 0 1 0 1 0 0 1 0 1 0 1 1 1 1 1 1 1 0 1 1
1 0 1 1 1 0 1 0 1 0 0 0 1 1 1 0 0 1 1 0 0 0 1 1 1
1 0 1 1 1 0 1 0 0 0 1 1 0 1 0 0 1 1 0 1 1 0 0 1 1
1 0 0 0 0 0 1 0 1 0 1 1 1 1 0 0 0 0 1 1 0 1 1 1 1
1 1 1 1 1 1 1 0 1 0 1 1 1 1 0 0 1 0 1 0 0 1 0 0 1
Jeremy
  • 22,188
  • 4
  • 68
  • 81
Rudy Ailabouni
  • 155
  • 1
  • 9
  • If you're reading text, you should use a `Reader` rather than an `InputStream`. Then, you can use a `BufferedReader`, which has a `readLine()` method. – Jeremy Mar 07 '17 at 20:05
  • Thing is, I am giving these method from the assignment and it has to be implemented exactly as it's given, I can't change anything in it. – Rudy Ailabouni Mar 07 '17 at 20:16
  • You can convert your `InputStream` into a `BufferedReader` like so: `new BufferedReader(new InputStreamReader(inputStream));` – Jeremy Mar 07 '17 at 20:18

3 Answers3

1

First, I suggest you use a Reader to read text. Then you can use a BufferedReader with its readLine() method to work with lines of text, rather than a stream of bytes.


Regardless, given your current code: once your read a \n, set a boolean flag to indicate that you've just saw a new line character. Then, as you begin reading the next line, switch on that flag such that if it's true, and you see a # as the next character, you should read until you see another \n. If it the flag is not true, then read the rest of the line as you are doing.

You may want to consider whitespace when finding the #, depending how lax you want this to be.

Jeremy
  • 22,188
  • 4
  • 68
  • 81
1

Why not use Files.lines instead of InputStream?

Files.lines(Paths.get("path_to_File.txt")).filter(s -> !s.contains("#"));// let's
//read all lines form the file and skip the lines with `#` symbol

Than we can convert each line to a list of Boolean:

s -> Stream.of(s.split(" ")).map("1"::equals).collect(Collectors.toList())// split 
string by ` ` (space) symbol and convert to Boolean "1" - true, "0" - false

Now let's put everything together:

List<List<Boolean>> qr = Files.lines(Paths.get("data/fromFile.txt"))
                .filter(s -> !s.contains("#")).map(
                        s -> Stream.of(s.split(" ")).map("1"::equals)
                            .collect(Collectors.toList())
                ).collect(Collectors.toList());

For the file:

# name: small
# type: bool matrix
# rows: 1
# columns: 3
1 1 1
1 0 1

Output will be

[true, true, true]
[true, false, true]
Anton Balaniuc
  • 10,889
  • 1
  • 35
  • 53
0

If you decide to use Reader then you may use regex to eleminate the lines which includes any character except '0' and '1'. You can find detail about regex usage below link. How to check if a string contains only digits in Java

You can modify regex expression for only 1 and 0 like String regex = "[0-1]+";

After you can use below sample code to get each character.

String s1="hello";
char[] ch=s1.toCharArray();
Community
  • 1
  • 1
Alper Derya
  • 237
  • 1
  • 9