How to make JTextField or JFormattedTextField accept input only if it matches a REGEX pattern?

让人想犯罪 __ 提交于 2019-12-08 05:43:31

问题


I want a few JTextField within my program to only accept new input if it matches an specific Pattern.

I know about JFormattedTextField's masks and that is not what I want here.

For each new input, the text should only accept the changes if those comply with the flow of an specific regex pattern.

This has to be done with regex because of "regex-demanding" situations, like if the input should receive parts of itself. This is better understood with an example:

Suppose my regex is "(\\d{2})-bk\\d{3}\\.\\1". With an input of "123-bk001.", the next inputted characters must be equal to the first group, meaning the 3 inputted characters should only be accepted if they equal 123, respectively. An input of "456-bk404." would require the next chars to be "456" instead.

How can I do it?


Edit:

This example is just to illustrate one of the situations that is hard to solve without regex, and my actual uses would not be limited to it. So, if possible, answers should be of the broader usability (as of the question's tittle), rather than specific to this example.

But if it's not possible or if it would be harder than implementing specific solutions for the few (3-5) different cases, feel free to tell.


回答1:


  • use DocumentFilter for removing or replace defined of unwanted chars (maybe could be possible with NavigationFilter.Bias)

  • you can to define own InputMask with InputVerifier




回答2:


My gut approach is to use the DocumentFilter and modify the Regex you're testing against based on how long your test string is. So if your test string is 10 characters long, the regex you'd use to test it is "(\\d{2})-bk\\d{3}\\." or "\\d\\d\\d-bk\\d\\d\\d\\d\\.". This would pass "123-bk0001.", but fail "123-bk000a.".

It would take some customization for each regex you would want to process (for example placing the parenthesis in the correct spot in the regex based on the length of the test string), but I don't think there's a way to make a regex dynamic based on length (which is what you're after).

import javax.swing.*;
import javax.swing.text.*;

public class JTextFieldSuperVerified extends Box{

    public JTextFieldSuperVerified() {
        super(BoxLayout.Y_AXIS);

        final JTextField textBox = new JTextField(20);

        ((AbstractDocument)textBox.getDocument()).setDocumentFilter(new DocumentFilter(){

            public void insertString(DocumentFilter.FilterBypass fb,int offset,String string,AttributeSet attr) throws BadLocationException{
                StringBuilder newString = new StringBuilder(textBox.getText());
                //Recreate the insert for testing
                newString.insert(offset, string);
                if(verifyText(newString.toString())){
                    fb.insertString(offset, string, attr);
                }

            }

            public void remove(DocumentFilter.FilterBypass fb, int offset, int length) throws BadLocationException{
                StringBuilder newString = new StringBuilder(textBox.getText());
                //Recreate the delete for testing
                newString.delete(offset, offset + length);
                if(verifyText(newString.toString())){
                    fb.remove(offset, length);
                }
            }


            public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException{
                StringBuilder newString = new StringBuilder(textBox.getText());
                //Recreate the replace for testing
                newString.replace(offset, offset + length, text);
                if(verifyText(newString.toString())){
                    fb.replace(offset, length, text, attrs);
                }
            }

            //make sure the change is allowed
            public boolean verifyText(String s){
                boolean result = true;
                //Our basic regex to test
                StringBuilder regexPattern = new StringBuilder("\\d\\d\\d-bk\\d\\d\\d\\d\\.\\1");


                if(s.length() < 15){
                    //How we modify the regex based on how long the string we're testing is
                    if(s.length() < 4)
                        regexPattern.delete(s.length() * 2, regexPattern.length());
                    else if(s.length() < 7)
                        regexPattern.delete(s.length() + 3, regexPattern.length());
                    else if(s.length() < 12)
                        regexPattern.delete((s.length() - 3) * 2 + 3, regexPattern.length());
                    else if(s.length() < 15){
                        regexPattern.insert((s.length() - 11) * 2, ')');
                        regexPattern.insert(0, '(');
                    }
                    System.out.println(regexPattern.toString());
                    result = s.matches(regexPattern.toString());

                }else{
                    //Fail everything over 14 chars
                    result = false;
                }

                return result;
            }

        });

        add(textBox);

    }

    public static void main(String[] args){
        final JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new JTextFieldSuperVerified());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}


来源:https://stackoverflow.com/questions/13610320/how-to-make-jtextfield-or-jformattedtextfield-accept-input-only-if-it-matches-a

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!