Hot questions for Using JTextField in regex

Question:

public void actionPerformed(ActionEvent e) {

    String usernamePat = " ^[a-z0-9]{3,15}&";
    String passwordPat = "((?=.*\\d)(?=.*[A-Za-z]).{6,20})";

    String strName = regname.getText();

    char[] mypass1 = pass1.getPassword();
    String strPass1 = new String(mypass1);

    char[] mypass2 = pass2.getPassword();
    String strPass2 = new String(mypass2);

    if (strName.isEmpty()) {
        obj.info("Please enter your username!", "Error");
        return;
    }

    if (strPass1.isEmpty()) {
        obj.info("Please enter your password!", "Error");
        return;
    }

    if (strPass2.isEmpty()) {
        obj.info("Please enter your password again!", "Error");
        return;
    }

    Pattern patU = Pattern.compile(usernamePat);
    Pattern patP = Pattern.compile(passwordPat);

    Matcher matU = patU.matcher(strName);
    Matcher matP = patP.matcher(strPass1);

    if (matU.matches()) {

        if (matP.matches()) {

            if (strPass1.equals(strPass2)) {

            } else {
                obj.info("Passwords dont match, please confirm it again", "Error");
            }

        } else {
            obj.info("You can only use alphabets/numbers in Password", "Error");
        }

    } else {
        obj.info("Please use only alphabets & numbers in Username", "Error");
    }

}

I got everything write on the place, I'm converting the inputs in strings, then the 3 else conditions are checking for empty fields and it is working fine. After those checks, I added regular expressions and to validate the input, and in that last nested if, I will put JDBC code to insert data into my table, but it's not getting pass the first username validation.

I don't get why, given the following input:

username : maisam123
password : abc123
confirm password: abc123


Answer:

There is a space at the start of your pattern (" ^[a-z0-9]{3,15}&") and a trailing ampersand (so only String(s) starting with a space and ending in an ampersand would pass). Also, you didn't include capital letters.

String usernamePat = "^[a-z0-9]{3,15}";

but, to allow upper-case letters it should be something like

String usernamePat = "^[A-Za-z0-9]{3,15}";

Question:

I have been trying to figure out a REGEX expressions which can filter characters which are not '-' or 0-9. This expression will be used with a document filter which will filter characters being inserted into JTextFields. Let me explain in more detail...

When a user enters a character into a JTextField a DocumentFilter checks the input using the replace method in the DocumentFilter class. Because the method is called every time a character is inserted the REGEX needed to be able to handle parts of an integer as the user builds the string. For example,

Key Press 1): Value = '-' PASS
Key Press 2): Value = '-1' PASS
Key Press 3): Value = '-10' PASS etc...

However the filter should not allow the combination '-0' or '--' and should pass the following cases,

Negative Symbol Only ('-')

Negative Number Without Zero Next To '-' ('-01' fail)

Positive Values (0122 and 122 pass)

Here is my code:

package regex;

import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;

public class CustomFilter extends DocumentFilter {

    private String regex = "((-?)([1-9]??))(\d)";

    /**
     * Called every time a new character is added.
     */
    @Override
    public void insertString(DocumentFilter.FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {

        String text = fb.getDocument().getText(0, fb.getDocument().getLength());
        text += string;

        if(text.matches(regex)) {
            super.insertString(fb, offset, string, attr);
        }
    }

    /**
     * Called when the user pastes in new text.
     */
    @Override
    public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {

        String string = fb.getDocument().getText(0, fb.getDocument().getLength());
        string += text;

        if(string.matches(regex)) {
            super.replace(fb, offset, length, text, attrs);
        }
    }

    @Override
    public void remove(FilterBypass fb, int offset, int length) throws BadLocationException {
        super.remove(fb, offset, length); // I may modify this later
    }
}

If you believe I am going about this in the wrong direction please let me know. I am open to a more simplistic option.


Answer:

Instead of all the alternations, factor it down to this

"^(?=[-\\d])(?:-(?!0))?\\d*$"

Explained

 ^                             # Beginning of string
 (?= [-\d] )                   # Must be a character in it
 (?:                           # Optional minus sign
      -
      (?! 0 )                       # If not followed by 0
 )?
 \d*                           # Optional digits [0-9]
 $                             # End of string

Mod:

With a little extra effort, you could get the partial valid string in capture group 1 and any remaining invalid trailing chars in group 2.

All this requires is to test if there is a match. Of course you need the matcher to get the groups.

Possible outcomes:

  1. The regex didn't match, the string is empty. Action: take no action.
  2. Regex matched. a. Action: If length of group 2 > 0, write to text field with group 1 string, and place cursor at the end. b. Action: If length of group 2 == 0, take no action, input is going correctly.

"^(?=.)((?:-(?>(?=0)|\\d*)|\\d*))(.*)$"

https://regex101.com/r/oxmZfa/1

Explained

 ^                             # Beginning of string

 (?= . )                       # Must be a character in the string

 (                             # (1 start), Template for pattial validity
      (?:
           -                             # The case for minus
           (?>                           # Atomic group for safety
                (?= 0 )                       # Don't capture 0 if it's ahead
             |                              # or,
                \d*                           # Any digits, 0 won't be first
           )
        |                              # or, the case for No minus
           \d*                           # Any digits
      )
 )                             # (1 end)

 ( .* )                        # (2), This is to be trimmed, stuff here doesn't match the template

 $                             # End of string

When the user submits the text use this regex to validate the input. If it doesn't match, the user did not add numbers to the field. Just popup a message that the input is incomplete.

"^(?=[-\\d])(?:-(?!0))?\\d+$"

Question:

I look all over the net and all the things I tried didn't work....

I found that I can use some JTextFormatterField but it didn't work.

Then I found that I can use DocumentFilter with regex and that what I did:

JTextField jFormattedTextFieldMoneyToConvert = new JTextField();
    ((AbstractDocument) jFormattedTextFieldMoneyToConvert.getDocument()).setDocumentFilter(new DocumentFilter(){
        Pattern regEx = Pattern.compile("^\\d+\\.?\\d*$");

        @Override
        public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
            Matcher matcher = regEx.matcher(text);
            if (!matcher.matches()) {
                return;
            }
            super.replace(fb, offset, length, text, attrs);
        }
    });

but it doesn't work...It accepts only digits. I want it to accept also dots. And I also need it to not to start with a dot and not to end with a dot.

what I'm doing wrong?


Answer:

This is probably the simplest code that works:

if (text.matches("\\d+(\\.\\d+)?"))

If there's a dot, it must be followed by some digits. If you want to allow a dot then no digits too, change the + to *:

if (text.matches("\\d+(\\.\\d*)?"))

Note that with String#matches(), the leading/trailing ^/$ are not necessary as they are implied, because the entire string must be matched for matches() to return true.

Allowing no leading digits too becomes trickier, because the regex (\d+)?(\.\d*) matches the blank string, so you need an alternation:

if (text.matches("\\d+(\\.\\d*)?|\\.\\d+"))

or a negative look ahead:

if (text.matches("(?!$)\\d*(\\.\\d*)?"))

The little look head asserts that the next position after the start is not the end (ie input is not blank).

Question:

Can anyone help me with the validation for JTextField which can only allow up to 3 digits before the decimal and up to 2 digits after the decimal?

I used regex \\d{3}\\.\\d{2} for InputVerifier. This is allowing exactly 3 and 2 before and after decimal. I need <=3 and <=2 before and after decimal.

My project only needs JTextField.


Answer:

To validate such strings, you can use the following regex:

^\d{0,3}\.\d{1,2}$

It will require at least 1 digit on the right side of the decimal, and the first part can be 0 to 3 digits long (due to {0,3} quantifier).

Note that it allows .2-like input.

Question:

I am creating a simple Java Swing application to validate an IP Address. I added a JTextField, JButton, JLabel. JTextField should accept AlphaNumeric values, ie - user can enter the name of a system or IP address of a system. I have added 2 validations for this scenario. While clicking JButton, first it will check for the format of the IP Address(to identify whether it is a name or IP address) using this pattern

"^([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})$".

If it is an IP address, then it will check whether it is a valid IP address or not using this pattern

"^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"

and display a message - valid or not.

Problem - If I enter an invalid IP address with proper format like -

299.143.154.167

the first validation is not getting successful.

    import java.awt.Color;
    import java.awt.Font;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JTextField;

    public class RegexDemo {
        public static String regExToCheckIPAddress = "^([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})$";
        public static Pattern pattern1;
        public static Matcher matcher1;
        public static String regExToCheckValidIPAddress = "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\." +
                                                          "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\." +
                                                          "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\." +
                                                          "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
        public static Pattern pattern2;
        public static Matcher matcher2;

        public static void main(String[] args) {
            JFrame frame = new JFrame("IP Address validation");
            JPanel panel = new JPanel();
            JTextField txtField = new JTextField();
            JButton btn = new JButton("Validate");
            JLabel lbl = new JLabel();
            lbl.setFont(new Font("Arial", Font.PLAIN, 12));
            lbl.setForeground(Color.RED);

            panel.setBounds(5,5,350,250);
            panel.setLayout(null);

            txtField.setBounds(5,5,130,25);
            btn.setBounds(20,40,80,25);
            lbl.setBounds(145,5,100,25);

            panel.add(txtField);
            panel.add(btn);
            panel.add(lbl);

            frame.add(panel);
            frame.setSize(330,300);
            frame.setLayout(null);
            frame.setLocationRelativeTo(null);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);

            String text = txtField.getText().trim();

            pattern1 = Pattern.compile(regExToCheckIPAddress);
            matcher1 = pattern1.matcher(text);

            pattern2 = Pattern.compile(regExToCheckValidIPAddress);
            matcher2 = pattern2.matcher(text);

            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent ae) {
                    if (matcher1.matches()) {
                        if (!matcher2.matches()) {
                            lbl.setText("Not a valid IP Address");
                        } else {
                            lbl.setText("Valid IP Address");
                        }
                    } else {
                        lbl.setText("Not an IP Address");
                    }
                }
            });
        }
    }

If I enter a alphanumeric name, it should display 'Not an IP Address', if I enter '299.143.154.167', it should display 'Not a valid IP Address', if '234.143.154.167' it should display 'Valid IP Address'.

This code is working fine, if I dont use Swing related components (without UI). Can any one help me on this?


Answer:

The problem is you are using the default text of the text field. You need to get the text when the button is pressed. After getting the text you need to create matchers.

You need to get the text and create matchers with the new text in actionPerformed method like this:

    public void actionPerformed(ActionEvent ae) {
        String text = txtField.getText().trim();
        matcher1 = pattern1.matcher(text);
        matcher2 = pattern2.matcher(text);
        if (matcher1.matches()) {
            if (!matcher2.matches()) {
                lbl.setText("Not a valid IP Address");
            } else {
                lbl.setText("Valid IP Address");
            }
        } else {
            lbl.setText("Not an IP Address");
        }
    }

Question:

I have a text field where a user is required to input information.

JTextField data = new JTextField();

I have a requirment that if a user enters in *. Then it should be treated as a regex wildcard for when I search for the data.

I am looping through a series of files and reading each line one by one.

for(int i = 0; i < files.length; i++) {
        BufferedReader reader = null;

        try {
            reader = new BufferedReader(new FileReader(files[i]));
            String text = null;

            while ((text = reader.readLine()) != null) {
                if(text.contains(data) return text; // Line that requires wildcard check
            }
        } catch(IOException e) {
            e.printStackTrace();
        } finally{
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (IOException e) {}
        }
    }

How could I achieve this wildcard check? I require to make the '*' become any character once entered by user.


Answer:

The problem is that the search string may contain other characters which would be significant in a regular expression, so it isn’t safe to just blindly convert * to .*.

You’ll want to use Pattern.quote on all parts of the search string except for the asterisks:

String[] parts = data.split("\\*");
Pattern pattern = Pattern.compile(
    Stream.of(parts).map(Pattern::quote).collect(Collectors.joining(".*")));

if (pattern.matcher(text).find()) {
    return text;
}

Breaking down the above statement:

  • data.split("\\*") splits the string by a regular expression that literally matches the * character, into an array of substrings. Examples:
    • "ab*cd"{ "ab", "cd" }
    • "1*2345*67"{ "1", "2345", "67" }
  • Stream.of(parts) creates a Stream from the array of substrings.
  • map(Pattern:quote) replaces each element in the Stream with its quoted equivalent, so any regex metacharacters (other than *) will be treated as ordinary characters. Thus, "1+1" in the original user input would actually match those three characters in the searched files.
  • collect(Collectors.joining(".*")) reassembles the elements in the stream into a single String, with .* between each quoted part.

On a side note, you can avoid writing a finally block by placing your BufferedReader in a try-with-resources statement:

String[] parts = data.split("\\*");
Pattern pattern = Pattern.compile(
    Stream.of(parts).map(Pattern::quote).collect(Collectors.joining(".*")));
Matcher matcher = pattern.matcher("");

for (File file : files) {
    try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
        String text;
        while ((text = reader.readLine()) != null) {
            if (matcher.reset(text).find()) {
                return text;
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Because BufferedReader implements AutoCloseable, an implicit finally block will be created which essentially does what you were doing: try to close the BufferedReader while suppressing any exception that might arise from the close attempt.

Question:

do you have an idea why there are no search results when I use an comma or semicolon in my search bar? I really get crazy...

Thanks ;-)

// Create searchbar
    searchBar = new JTextField(15);
    searchButton.setVisible(false);
// Add to panel
    panel.add(searchBar);
    getRootPane().setDefaultButton(searchButton);
    add(panel, BorderLayout.PAGE_START);

...
...
...

// Integrate ActionListener for textfilter
    searchButton.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {

             String text = searchBar.getText();


            if (text.length() == 0) {
                tableRowSorter.setRowFilter(null);
            } else {
                tableRowSorter.setRowFilter(RowFilter.regexFilter("(?i)" + text));


            }
        }

    });![Panel with search box][1]


Answer:

Comma and semicolon are used like metacharacters or escape sequences. Try to use quote() method to escape them:

tableRowSorter.setRowFilter(RowFilter.regexFilter("(?i)" + Pattern.quote(text)));