Trouble using regex in DocumentFilter for JTextField
Asked Answered
T

1

1

I am using a DocumentFilter on a JTextField which is used to enter in the amount of time an employee has worked. the filter is to ensure that the limit of input is only 4 characters long and to only allow numbers. A decimal may or may not be used but should only be allowed to be entered once, once a decimal is entered, there should only allow for one more number. Meaning 9.5 or 10.5 should be accepted and 8.45 is not.

So far I am able to get about half of the total desired functionality. No more than 4 characters can be entered and only digits are allowed. The latter is accomplished using the replaceAll("[^0-9.]", "") method.

I've spent a lot of time watching tutorials, reading documentation and related questions such as this, this, and especially this, but can't seem to get a regex to perform fully. One thing in particular than I can't figure out is why exactly a regex of [^0-9] will successfully only allow digits, but ^\\d wont unless enclosed as a character class such as [\\d]

My filter code is below:

import java.awt.Toolkit;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;

public class TimeWorkedFilter extends DocumentFilter {

    private int maxCharacters;    

    public TimeWorkedFilter(int maxChars) {
        maxCharacters = maxChars;
    }
//"[^0-9.]
    public void insertString(FilterBypass fb, int offs, String str, AttributeSet a)
            throws BadLocationException {

        if ((fb.getDocument().getLength() + str.length()) <= maxCharacters)
            super.insertString(fb, offs, str.replaceAll("[^0-9.]", ""), a);
        else
            Toolkit.getDefaultToolkit().beep();
    }

    public void replace(FilterBypass fb, int offs, int length, String str, AttributeSet a)
            throws BadLocationException {

        if ((fb.getDocument().getLength() + str.length()
                - length) <= maxCharacters)
            super.replace(fb, offs, length, str.replaceAll("[^0-9.]", ""), a);
        else
            Toolkit.getDefaultToolkit().beep();
    }
}
Theobald answered 6/5, 2014 at 18:4 Comment(2)
number filter is quite often aksed hereGenealogy
To answer your last question: ^ has a special meaning inside a character class ([]) definition. Otherwise, it simply means "start of string/line".Urogenital
C
2

"I can't figure out is why exactly a regex of [^0-9] will successfully only allow digits"

The str passed to your overridden methods (in terms of typing) is only a single character, as the filter methods are called every time you type in a character. The regex [^0-9] means not numbers. So when you do str.replaceAll("[^0-9.]", ""), you are giving the filter permission to insert the character to the text field, as as long as it is a number, other wise it will add an empty character/string, giving the effect of the user not being able to enter a letter.

That being said, as for the real question

" the filter is to ensure that the limit of input is only 4 characters long and to only allow numbers. A decimal may or may not be used but should only be allowed to be entered once, once a decimal is entered, there should only allow for one more number. Meaning 9.5 or 10.5 should be accepted and 8.45 is not."

As mentioned above, the str passed to the method is a single character, so if you try to pass a complete regex to the str.replaceAll() to match say 8.9, it won't work. The regex in the replaceAll() is meant to just check the single character (in this case).

What you can do instead it get the text from the document, concatenate the str to the document and see if the total text matches() a complete regex. Something like

public void replace(FilterBypass fb, int offs, int length, String str, AttributeSet a)
        throws BadLocationException {

    String text = fb.getDocument().getText(0, fb.getDocument().getLength());
    text += str;
    if ((fb.getDocument().getLength() + str.length()
            - length) <= maxCharacters && text.matches("^[0-9]+[.]?[0-9]{0,1}$")) {
        super.replace(fb, offs, length, str, a);
    } else {
        Toolkit.getDefaultToolkit().beep();
    }
}

Not sure if that's the exact regex your looking for. Regex is not my forte. I got the regex from this question

Cayser answered 6/5, 2014 at 19:5 Comment(1)
excellent answer. I didn't realize I was failing before because the filter was taking it per character. I guess I should have but I'm still pretty new to Java and basically am just teaching myself.Theobald

© 2022 - 2024 — McMap. All rights reserved.