简体   繁体   中英

Java REGEX With Document Filter

I have been trying to figure out a REGEX expressions which can filter characters which are not '-' or 0-9. This expression will be used with a document filter which will filter characters being inserted into JTextFields. Let me explain in more detail...

When a user enters a character into a JTextField a DocumentFilter checks the input using the replace method in the DocumentFilter class. Because the method is called every time a character is inserted the REGEX needed to be able to handle parts of an integer as the user builds the string. For example,

Key Press 1): Value = '-' PASS
Key Press 2): Value = '-1' PASS
Key Press 3): Value = '-10' PASS etc...

However the filter should not allow the combination '-0' or '--' and should pass the following cases,

Negative Symbol Only ('-')

Negative Number Without Zero Next To '-' ('-01' fail)

Positive Values (0122 and 122 pass)

Here is my code:

package regex;

import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;

public class CustomFilter extends DocumentFilter {

    private String regex = "((-?)([1-9]??))(\d)";

    /**
     * Called every time a new character is added.
     */
    @Override
    public void insertString(DocumentFilter.FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {

        String text = fb.getDocument().getText(0, fb.getDocument().getLength());
        text += string;

        if(text.matches(regex)) {
            super.insertString(fb, offset, string, attr);
        }
    }

    /**
     * Called when the user pastes in new text.
     */
    @Override
    public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {

        String string = fb.getDocument().getText(0, fb.getDocument().getLength());
        string += text;

        if(string.matches(regex)) {
            super.replace(fb, offset, length, text, attrs);
        }
    }

    @Override
    public void remove(FilterBypass fb, int offset, int length) throws BadLocationException {
        super.remove(fb, offset, length); // I may modify this later
    }
}

If you believe I am going about this in the wrong direction please let me know. I am open to a more simplistic option.

I finally figured it out right after posting this question! (funny how things work out)

Regex Expression: ^(-{1})|(-[1-9])|(-[1-9]([0-9]{1,}))|([0-9]{1,})$

For anyone who didn't know (like I) | is an OR symbol in regex. So this expression will allow values to pass by matching the string in steps,

(-{1}) Passes one '-'

(-[1-9]) Passes a '-' which one non zero integer is appended to

(-[1-9]([0-9]{1,})) Passes a '-' with one non zero integer appended to and also allows any number of integers after this pass

([0-9]{1,}) Passes any positive integer regardless of the starting integer

Hope this helps!

Instead of all the alternations, factor it down to this

"^(?=[-\\\\d])(?:-(?!0))?\\\\d*$"

Explained

 ^                             # Beginning of string
 (?= [-\d] )                   # Must be a character in it
 (?:                           # Optional minus sign
      -
      (?! 0 )                       # If not followed by 0
 )?
 \d*                           # Optional digits [0-9]
 $                             # End of string

Mod:

With a little extra effort, you could get the partial valid string in
capture group 1 and any remaining invalid trailing chars in group 2.

All this requires is to test if there is a match.
Of course you need the matcher to get the groups.

Possible outcomes:

  1. The regex didn't match, the string is empty.
    Action: take no action.
  2. Regex matched.
    a . Action: If length of group 2 > 0, write to text field
    with group 1 string, and place cursor at the end.
    b . Action: If length of group 2 == 0, take no action, input is going correctly.

"^(?=.)((?:-(?>(?=0)|\\\\d*)|\\\\d*))(.*)$"

https://regex101.com/r/oxmZfa/1

Explained

 ^                             # Beginning of string

 (?= . )                       # Must be a character in the string

 (                             # (1 start), Template for pattial validity
      (?:
           -                             # The case for minus
           (?>                           # Atomic group for safety
                (?= 0 )                       # Don't capture 0 if it's ahead
             |                              # or,
                \d*                           # Any digits, 0 won't be first
           )
        |                              # or, the case for No minus
           \d*                           # Any digits
      )
 )                             # (1 end)

 ( .* )                        # (2), This is to be trimmed, stuff here doesn't match the template

 $                             # End of string

When the user submits the text use this regex to validate the input.
If it doesn't match, the user did not add numbers to the field.
Just popup a message that the input is incomplete.

"^(?=[-\\\\d])(?:-(?!0))?\\\\d+$"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM