Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
485 views
in Technique[技术] by (71.8m points)

java - Trouble using regex in DocumentFilter for JTextField

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();
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

"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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...