Проблема с использованием регулярных выражений в DocumentFilter для JTextField

Я использую DocumentFilter на JTextField, который используется для ввода количества времени, отработанного сотрудником. фильтр должен гарантировать, что предел ввода составляет всего 4 символа и разрешает только числа. Десятичное число может использоваться или не использоваться, но должно быть разрешено вводить только один раз, после ввода десятичного числа должно быть разрешено только еще одно число. Значение 9,5 или 10,5 должно быть принято, а 8,45 - нет.

На данный момент я могу получить около половины желаемого функционала. Можно ввести не более 4 символов, разрешены только цифры. Последнее достигается с помощью метода replaceAll("[^0-9.]", "").

Я провел много времени за просмотром руководств, чтением документации и связанными вопросами, такими как это, это и особенно это, но может похоже, регулярное выражение не работает полностью. В частности, я не могу понять, почему именно регулярное выражение [^0-9] будет успешно разрешать только цифры, а ^\\d не будет, если оно не заключено в класс символов, такой как [\\d]

Мой код фильтра ниже:

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

person exit_1    schedule 06.05.2014    source источник
comment
здесь довольно часто спрашивают числовой фильтр   -  person mKorbel    schedule 06.05.2014
comment
Чтобы ответить на ваш последний вопрос: ^ имеет особое значение внутри определения класса символов ([]). В противном случае это просто означает начало строки/строки.   -  person tenub    schedule 06.05.2014


Ответы (1)


«Я не могу понять, почему именно регулярное выражение [^0-9] успешно разрешает только цифры»

str, переданный вашим переопределенным методам (с точки зрения набора текста), представляет собой только один символ, поскольку методы фильтра вызываются каждый раз, когда вы вводите символ. Регулярное выражение [^0-9] означает не числа. Поэтому, когда вы делаете str.replaceAll("[^0-9.]", ""), вы даете фильтру разрешение на вставку символа в текстовое поле, если это число, в противном случае он добавит пустой символ/строку, создавая эффект, что пользователь не может ввести букву.

При этом, что касается реального вопроса

" фильтр должен гарантировать, что ограничение на ввод составляет всего 4 символа, и разрешать только числа. Десятичное число может использоваться или не использоваться, но должно быть разрешено вводить только один раз, после ввода десятичного числа должно быть разрешено только для еще одного числа. Значение 9,5 или 10,5 должно быть принято, а 8,45 - нет».

Как упоминалось выше, str, переданный методу, представляет собой одиночный символ, поэтому, если вы попытаетесь передать полное регулярное выражение в str.replaceAll(), чтобы оно соответствовало, скажем, 8.9, это не сработает. Регулярное выражение в replaceAll() предназначено для проверки одного символа (в данном случае).

Вместо этого вы можете получить текст из документа, объединить str с документом и посмотреть, является ли общий текст matches() полным регулярным выражением. Что-то типа

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

Не уверен, что это именно то регулярное выражение, которое вы ищете. Regex не моя сильная сторона. Я получил регулярное выражение из этот вопрос

person Paul Samsotha    schedule 06.05.2014
comment
отличный ответ. Раньше я не осознавал, что терпел неудачу, потому что фильтр принимал его за символ. Я думаю, что должен был, но я все еще новичок в Java и в основном просто учусь. - person exit_1; 06.05.2014