0

I am trying to implement a registration panel with username password and email only. I put all the usernames and passwords in a text file "usernames.txt". But my problem is not working properly if user clicks the submit button and the username already exists nothing happens( it should display JOptionPane with text "Username already exists!" ). here is my code :

submitButton.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            BufferedReader br = null;
            try {
                br = new BufferedReader(new FileReader("usernames.txt"));
            } catch (FileNotFoundException e2) {
                // TODO Auto-generated catch block
                e2.printStackTrace();
            }
            try {   
                String line = br.readLine();
                StringBuilder sb = new StringBuilder();
                Pattern usernameAndPasswordPattern = Pattern.compile("^(\\S+) (\\S+)$");
                while (line != null) {
                    sb.append(line); // 
                    sb.append(System.lineSeparator()); // 
                    line = br.readLine();
                }
                String everything = sb.toString();
                Matcher userNameAndPasswordMatcher = usernameAndPasswordPattern.matcher(everything);

                //if username exists!
                while (userNameAndPasswordMatcher.matches()) {
                    String username = userNameAndPasswordMatcher.group(1);
                    String password = userNameAndPasswordMatcher.group(2);

                    if (username.equals(usernameTextField.getText())) {
                        int result = JOptionPane.showConfirmDialog(null, "Username already exists!", "Registration incomplete", JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE);
                    }
                }

            } catch (IOException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            } finally {
                try {
                    br.close();
                } catch (IOException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
            }                       
        }
    });

Here you can see a pic from my panel

enter image description here

j.DOE
  • 35
  • 6
  • the call `Pattern.matches(""+usernameTextField.getText(), line)` expects a valid RegEx as the first string and does not simply compare two lines. You want to use `line.equals(""+usernameTextField.getText())`, see https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html#matches%28java.lang.String,%20java.lang.CharSequence%29 for reference – Japu_D_Cret Mar 30 '17 at 10:13
  • @Japu_D_Cret i think `line.equals` wont work because lines in the usernames.txt are in the format {Username} {Password} and if i compare them with `line.equals` i will compare the password too. – j.DOE Mar 30 '17 at 10:29
  • @jDOE I added a more detailed answer where you could also easily extract the password and handle everything pretty neetly – Japu_D_Cret Mar 30 '17 at 10:49

2 Answers2

2

You say that the lines in your file consist of a username AND a password. Yet you are testing for a match like this:

boolean matches = Pattern.matches(""+usernameTextField.getText(), line);  

Problems with the above.

  1. The match verb for a Pattern or Matcher means "it matches the entire string".

  2. The first argument to Pattern.matches(String, String) is supposed to be a regex represented as a string, not just any old string. Now if your alphabet for user names is suitable restricted, it may work to use the name as a regex. But it is a bad idea.

  3. Even after changuing the "match" to "find", you could still potentially have the supplied user name match either a password or part of a user name in the file.

Taken out of context (i.e. ignoring point 3), it would be better to do the match like this:

boolean matches = line.contains(""+usernameTextField.getText());  

or maybe

boolean matches = Pattern.find(
    Pattern.quote(""+usernameTextField.getText()), line);  

However, that still has the problem that you could get false matches; e.g. matches on partial user names ... or even passwords.

Therefore the correct solution would be either to craft a regex that matches on the entire username field in your file, or split the lines into fields (e.g. String.split and then use String.equals to test the appropriate field against the username that has been provided.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
2

although the answer from @StephenC works for your case it is pretty specific and I think it could be tackled more elegantly.

How about you define a RegEx-Pattern which splits the username and Password into two groups, since you stated

the usernames.txt are in the format {Username} {Password}

you could use the RegEx ^(\S+) (\S+)$, which means a non-null set of non-whitespace characters in group 1 followed by a space and then a non-null set of non-whitespace characters(check it out at https://regex101.com/)

Here is it implemented with Javas own libraries

private static final Pattern usernameAndPasswordPattern = Pattern.compile("^(\\S+) (\\S+)$");

public static void checkInput(String input) throws IOException {
  try(BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(new File("usernames.txt"))))) {
    String line = br.readLine();
    while(line != null) {
      Matcher userNameAndPasswordMatcher = usernameAndPasswordPattern.matcher(line);

      if(userNameAndPasswordMatcher.matches()) {
        String username = userNameAndPasswordMatcher.group(1);
        String password = userNameAndPasswordMatcher.group(2);

        if(username.equals(input)) {
          System.out.println("Username exists!");
          System.out.println("Password is: " + password);
          break;
        }
      }
      line = br.readLine();
    }
  }
}

I used this to test it

public static void main(String[] args) throws IOException {
  System.out.println("main > calling checkInput('Gary')..");
  checkInput("Gary");
  System.out.println("main > calling checkInput('Donald')..");
  checkInput("Donald");
  System.out.println("main > calling checkInput('Gordon')..");
  checkInput("Gordon");
}

and here is my test data

Peter 123peter567
Gary newman
Gordon fr33m4n

and my output

main > calling checkInput('Gary')..
Username exists!
Password is: newman
main > calling checkInput('Donald')..
main > calling checkInput('Gordon')..
Username exists!
Password is: fr33m4n
Japu_D_Cret
  • 632
  • 5
  • 18
  • can this work if i rewrite my code to work with stringbuilder. I mean when i read every line from the textfile i append it to a string builder and then i search for matches in the entire string builder, not separately for every single line? See my edits in the post above. I make it your way but in that case i am looking for matches in the `everything`. That way stopped working again. – j.DOE Mar 30 '17 at 21:09