如何使JTextField或JFormattedTextField仅在与REGEX模式匹配时接受输入?

时间:2012-11-28 16:54:33

标签: java swing formatting block mask

我希望程序中的一些JTextField只接受与特定Pattern匹配的新输入。

我知道JFormattedTextField的面具,我想要的东西。

对于每个新输入,如果这些更改符合特定正则表达式模式的流程,则文本应仅接受更改。

这必须通过正则表达式完成,因为“正则表达式要求”的情况,比如输入应该接收自身的一部分。通过一个例子可以更好地理解这一点:

假设我的正则表达式为"(\\d{2})-bk\\d{3}\\.\\1"。 输入"123-bk001."时,下一个输入的字符必须等于第一组,这意味着只有3个输入字符分别等于123才能被接受。 输入“456-bk404”。将要求下一个字符为"456"

我该怎么做?


修改

这个例子只是为了说明没有正则表达式难以解决的情况之一,我的实际用途不仅限于此。所以,如果可能的话,答案应该是更广泛的可用性(从问题的角度来看),而不是具体到这个例子。

但是,如果不可能或者为少数(3-5个)不同案例实施特定解决方案会更难,请随时告诉。

2 个答案:

答案 0 :(得分:2)

答案 1 :(得分:0)

我的直觉方法是使用DocumentFilter并根据测试字符串的长度修改您正在测试的正则表达式。因此,如果您的测试字符串长度为10个字符,那么您用来测试它的正则表达式是"(\\d{2})-bk\\d{3}\\.""\\d\\d\\d-bk\\d\\d\\d\\d\\."。这将通过"123-bk0001.",但无法"123-bk000a."

对于你想要处理的每个正则表达式需要一些自定义(例如,根据测试字符串的长度将括号放在正则表达式中的正确位置),但我认为没有办法制作基于长度的正则表达式动态(这就是你所追求的)。

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);
    }
}