Creating a menu for user to make a choice and determine if it is a Palindrome

146 Views Asked by At

Example output

file1.txt contents

I have to do a project to determine whether user input is a Palindrome (same letters forwards as backwards). I must create a menu and the user selects whether to input through the console or through a file. I had no issue with reading from the console. I am having trouble producing the correct output through reading Files however.

For a file to be a palindrome, the whole file must be able to be read forwards and backwards and be equal. Then the file contents must be printed and labeled as a Palindrome. I am able to determine if a string is a palindrome within the file, but not the whole file itself. I tried to use .hasNextLine() and compare the lines, but the output is not exactly what is desired.

import java.io.File;
import java.io.FileNotFoundException;
import java.util.InputMismatchException;
import java.util.Scanner;

public class PalindromeMachine { //begin class


  public static void main(String[] args) { //begin main


    boolean choice1 = false;
    boolean choice2 = false;
    boolean choice3 = false;


    while (choice3 == false) {

      //create a menu
      System.out.println("Welcome to the Palindrome Machine!");
      for (int i = 0; i < 35; i++) {
         System.out.print("-");
      }



      System.out.printf("\n1. Read one word from the keyboard");
      System.out.printf("\n2. Read one or more words from a file");
      System.out.printf("\n3. Exit");
      System.out.printf("\nEnter your selection: ");


      //gather user input
      Scanner user = new Scanner(System.in);
  
      try {
        int num = user.nextInt();
    
        if (num > 3 || num < 1) {
          System.out.println("Invalid menu option");
    
    
        }

        if (num == 1) {
          choice1 = true;

        }

        if (num == 2) {
          choice2 = true;

        }
        if (num == 3) {
          choice3 = true;

        }
      } catch (InputMismatchException e) {
  
        System.out.println("Invalid menu option");
  
      }




      //based on user selection, read in the word  or read in lines from a file

      while (choice1 == true) {

        System.out.printf("Enter the word you would like to check: ");

        String checkThis = user.next();
        int front = 0;
        int back = checkThis.length() - 1;
  


        while (front < back) {
    
          if (checkThis.charAt(front) != checkThis.charAt(back)) {
            choice1 = false;
            System.out.printf("%s: this word is not a palindrome\n\n", checkThis);
    
          } 
    
          front++;
          back--;     
      


        }
  
        if (choice1 == true) {
          System.out.printf("%s: this word is a palindrome\n\n", checkThis);
          choice1 = false;
      
        }





      } //end while for choice 1


      //read from file and determine if palindrome



      while (choice2 == true) {
        System.out.printf("Enter the file you would like to check: ");
        String name;
        name = user.nextLine();
        try {
    
          File pali = new File(name);
          Scanner userRead = new Scanner(pali);
    
          while (userRead.hasNextLine()) {
    
        
      
            String checkThis = userRead.nextLine();
        
        
        
        
            //palindrome info
            int front = 0;
            int back = checkThis.length() - 1;
  


            while (front < back) { //palindrome
    
              if (checkThis.charAt(front) != checkThis.charAt(back)) {
                choice2 = false;
                System.out.printf("\n%s: this file is not a palindrome",
                    checkThis);
    
              } 
    
              front++;
              back--;     
    

            } //end palindrome
      
            if (choice2 == true && userRead.hasNextLine() != false) {
              System.out.printf(checkThis
                   + ": this file is a palindrome\n");
              choice2 = false;
          
        
        
            } else {
              System.out.println("");
              System.out.printf(checkThis);
            }
          } //end of while the file has text
       
  
  
        } catch (FileNotFoundException e) {
    
          System.out.printf("\nInvalid file");
    
    
    
        }
  
  






      } // end choice 2





      //loop until the user exits + catch inputmismatch

    } // end while it loop until exit

  } //end main



} //end class
1

There are 1 best solutions below

1
rzwitserloot On

If your intent is to read the entire file and then check if the entire contents are a palindrome or not, then lines in general are a bit of a complicated mess.

Is:

Hello, there!

!ereht ,olleH

A palindromic file? Note that it ends in a newline, so if you attempt to compare byte-for-byte, it's not. If the intent is that it is supposed to 'count', then presumably you'd first trim (lop any whitespace off of the front and back of the entire thing) and then compare byte-for-byte?

If the file's encoding involves characters smearing out over bytes (common - UTF_8, the most common encoding, can do that for any character that isn't simple ASCII), byte-for-byte fails immediately, so I guess character-by-character? Java's 'character' is actually part of surrogate pairs, so symbols from the higher unicode planes, such as emoji, will thus immediately cause trouble (as the emoji is two characters, and therefore won't be the same backwards and forwards). Just go with 'eh, whatever, no files will contain emoji'? Or try to compare codepoints instead?

What about commas, capitals, and other symbol characters? Is this:

Hello, there!
Ereht, olleh!

supposed to 'count'? If you look at Just the actually letters and forget about casing, it is. But a char-by-char comparison will obviously fail. Before you say: That's not palindromic, the usual "A man, a plan, a canal, Panama!" requires that you disregard non-letters and disregard casing.

In any case, it all starts with reading the entire file as a string; Scanner is designed to read tokens (tokens are the things in between the separator), and it has some ugly misplaced baggage in the form of the nextLine() method that you probably shouldn't be using. In any case, it can't read the entire file in one go which makes this vastly more complicated than it needs to be, so step 1 is do not use it.

There's the new file API which is great for this:

import java.nio.file.*;

Path p = Paths.get(fileName);
String contents = Files.readString(p);

That will read the entire contents. We can then remove everything that isn't a letter from it:

contents.toLowerCase().replaceAll("[^a-z]", "");

That thing is a 'regular expression' which is a mini language for text manipulation. [^...] is 'match any character that isn't mentioned here', and a-z is naturally, everything from a to z. In other words, that says: Take the input, lowercase everything, then replace all non-letters with blank, thus giving you only the letters. I turns "A man, a plan, a canal, Panama!" into "amanaplanacanalpanama".

It even gets rid of newlines entirely.

Now you can use the principle at work in your code (start from the beginning and end, fetch the characters there, compare them. If not equal - it is not a palindrome. If equal, increment your 'front pointer', decrement your 'back pointer', and keep going with the comparisons until your pointers are identical, then it is a palindrome.

Scanner has only two uses:

  • Keyboard input. In which case you should never use .nextLine() (nextLine is broken. It does what the javadoc says it does, which not what anyone expects, hence, do not use it for this) - and always call .useDelimiter("\\R") immediately after making the scanner. This configures it the way you'd expect. Use .nextX() calls to fetch info. next() for strings .nextInt() for integers, etc. All next calls will read entire lines.
  • Tokenizing inputs. This is only useful if the input is defined in terms of tokens separated by separators. Only a few formats follow that kinda rule. Even your usual 'CSV' files don't, not really - you need custom CSV parsers for that.

"Read an entire file to see if it is palindromic" fits neither use.