Java Demo Application using Regular Expressions

Tutorial | Tools & Languages | Examples | Books & Reference |

grep | PowerGREP | RegexBuddy | RegexMagic |

EditPad Pro |

Delphi | GNU (Linux) | Groovy | Java | JavaScript | .NET | PCRE (C/C++) | Perl | PHP | POSIX | PowerShell | Python | R | REALbasic | Ruby | Tcl | VBScript | Visual Basic 6 | wxWidgets | XML Schema | XQuery & XPath |

MySQL | Oracle | PostgreSQL |

RegexBuddy Get RegexBuddy and easily use the power of regular expressions in Java.

Learn how to use the java.util.regex package.

Download the demo application and complete source code

package regexdemo;

import java.util.regex.*;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

/**
 * Regular Expressions Demo
 * Demonstration showing how to use the java.util.regex package that is part of 
 * the JDK 1.4 and later
 * Copyright (c) 2003 Jan Goyvaerts.  All rights reserved.
 * Visit http://www.regular-expressions.info for a detailed tutorial 
 * to regular expressions.
 * This source code is provided for educational purposes only, without any warranty of any kind.
 * Distribution of this source code and/or the application compiled 
 * from this source code is prohibited.
 * Please refer everybody interested in getting a copy of the source code to
 * http://www.regular-expressions.info
 * @author Jan Goyvaerts
 * @version 1.0
 */

public class FrameRegexDemo extends JFrame {

  // Code generated by the JBuilder 9 designer to create the frame depicted below
  // has been omitted for brevity

  Java Demo Application using Regular Expressions

  /** The easiest way to check if a particular string matches a regular expression
   *  is to simply call String.matches() passing the regular expression to it.
   *  It is not possible to set matching options this way, so the checkboxes
   *  in this demo are ignored when clicking btnMatch.<p>
   *
   *  One disadvantage of this method is that it will only return true if 
   *  the regex matches the *entire* string.  In other words, an implicit \A 
   *  is prepended to the regex and an implicit \z is appended to it.
   *  So you cannot use matches() to test if a substring anywhere in the string
   *  matches the regex.<p>
   *
   *  Note that when typing in a regular expression into textSubject,
   *  backslashes are interpreted at the regex level.
   *  Typing in \( will match a literal ( and \\ matches a literal backslash.
   *  When passing literal strings in your source code, you need to escape
   *  backslashes in strings as usual.
   *  The string "\\(" matches a literal ( character
   *  and "\\\\" matches a single literal backslash.
   */
  void btnMatch_actionPerformed(ActionEvent e) {
    textReplaceResults.setText("n/a");
    // Calling the Pattern.matches static method is an alternative way
    // if (Pattern.matches(textRegex.getText(), textSubject.getText())) {
    try {
      if (textSubject.getText().matches(textRegex.getText())) {
        textResults.setText("The regex matches the entire subject");
      }
      else {
        textResults.setText("The regex does not match the entire subject");
      }
    } catch (PatternSyntaxException ex) {
      textResults.setText("You have an error in your regular expression:\n" +
                          ex.getDescription());
    }
  }

  /** The easiest way to perform a regex search-and-replace on a string
   *  is to call the string's replaceFirst() and replaceAll() methods.
   *  replaceAll() will replace all substrings that match the regular expression
   *  with the replacement string, while replaceFirst() will only replace 
   *  the first match.<p>
   *
   *  Again, you cannot set matching options this way, so the checkboxes
   *  in this demo are ignored when clicking btnMatch.<p>
   *
   *  In the replacement text, you can use $0 to insert the entire regex match,
   *  and $1, $2, $3, etc. for the backreferences (text matched by the part in the
   *  regex between the first, second, third, etc. pair of round brackets)<br>
   *  \$ inserts a single $ character.<p>
   *
   *  $$ or other improper use of the $ sign throws an IllegalArgumentException.
   *  If you reference a group that does not exist (e.g. $4 if there are only
   *  3 groups), throws an IndexOutOfBoundsException.
   *  Be sure to properly handle these exceptions if you allow the end user 
   *  to type in the replacement text.<p>
   *
   *  Note that in the memo control, you type \$ to insert a dollar sign,
   *  and \\ to insert a backslash.  If you provide the replacement string as a
   *  string literal in your Java code, you need to use "\\$" and "\\\\".
   *  This is because backslashes need to be escaped in Java string literals too.
   */
  void btnReplace_actionPerformed(ActionEvent e) {
    try {
      textReplaceResults.setText(
        textSubject.getText().replaceAll(
          textRegex.getText(), textReplace.getText())
      );
      textResults.setText("n/a");
    } catch (PatternSyntaxException ex) {
      // textRegex does not contain a valid regular expression
      textResults.setText("You have an error in your regular expression:\n" +
                          ex.getDescription());
      textReplaceResults.setText("n/a");
    } catch (IllegalArgumentException ex) {
      // textReplace contains inapropriate dollar signs
      textResults.setText("You have an error in the replacement text:\n" +
                          ex.getMessage());
      textReplaceResults.setText("n/a");
    } catch (IndexOutOfBoundsException ex) {
      // textReplace contains a backreference that does not exist
      // (e.g. $4 if there are only three groups)
      textResults.setText("Non-existent group in the replacement text:\n" +
                          ex.getMessage());
      textReplaceResults.setText("n/a");
    }
  }

  /** Show the results of splitting a string. */
  void printSplitArray(String[] array) {
    textResults.setText(null);
    for (int i = 0; i < array.length; i++) {
      textResults.append(Integer.toString(i) + ": \"" + array[i] + "\"\r\n");
    }
  }

  /** The easiest way to split a string into an array of strings is by calling
   *  the string's split() method.  The string will be split at each substring
   *  that matches the regular expression.  The regex matches themselves are
   *  thrown away.<p>
   *
   *  If the split would result in trailing empty strings, (when the regex matches
   *  at the end of the string), the trailing empty strings are also thrown away.
   *  If you want to keep the empty strings, call split(regex, -1).  The -1 tells
   *  the split() method to add trailing empty strings to the resulting array.<p>
   *
   *  You can limit the number of items in the resulting array by specifying a
   *  positive number as the second parameter to split().  The limit you specify
   *  it the number of items the array will at most contain.  The regex is applied
   *  at most limit-1 times, and the last item in the array contains the unsplit
   *  remainder of the original string.  If you are only interested in the first
   *  3 items in the array, specify a limit of 4 and disregard the last item.
   *  This is more efficient than having the string split completely.
   */
  void btnSplit_actionPerformed(ActionEvent e) {
    textReplaceResults.setText("n/a");
    try {
      printSplitArray(textSubject.getText().split(textRegex.getText() 
                                                  /*, Limit*/ ));
    } catch (PatternSyntaxException ex) {
      // textRegex does not contain a valid regular expression
      textResults.setText("You have an error in your regular expression:\n" +
                          ex.getDescription());
    }
  }

  /** Figure out the regex options to be passed to the Pattern.compile()
   *  class factory based on the state of the checkboxes.
   */
  int getRegexOptions() {
    int Options = 0;
    if (checkCanonEquivalence.isSelected()) {
      // In Unicode, certain characters can be encoded in more than one way.
      // Many letters with diacritics can be encoded as a single character
      // identifying the letter with the diacritic, and encoded as two
      // characters: the letter by itself followed by the diacritic by itself
      // Though the internal representation is different, when the string is
      // rendered to the screen, the result is exactly the same.
      Options |= Pattern.CANON_EQ;
    }
    if (checkCaseInsensitive.isSelected()) {
      // Omitting UNICODE_CASE causes only US ASCII characters to be matched
      // case insensitively.  This is appropriate if you know beforehand that 
      // the subject string will only contain US ASCII characters
      // as it speeds up the pattern matching.
      Options |= Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE;
    }
    if (checkDotAll.isSelected()) {
      // By default, the dot will not match line break characters.
      // Specify this option to make the dot match all characters, 
      // including line breaks
      Options |= Pattern.DOTALL;
    }
    if (checkMultiLine.isSelected()) {
      // By default, the caret ^, dollar $  only match at the start 
      // and the end of the string.  Specify this option to make ^ also match 
      // after line breaks in the string, and make $ match before line breaks.
      Options |= Pattern.MULTILINE;
    }
    return Options;
  }

  /** Pattern constructed by btnObject */
  Pattern compiledRegex;

  /** Matcher object that will search the subject string using compiledRegex */
  Matcher regexMatcher;
  JLabel jLabel8 = new JLabel();
  JButton btnAdvancedReplace = new JButton();

  /** If you will be using a particular regular expression often,
   *  you should create a Pattern object to store the regular expression.
   *  You can then reuse the regex as often as you want by reusing the
   *  Pattern object.<p>
   *
   *  To use the regular expression on a string, create a Matcher object
   *  by calling compiledRegex.matcher() passing the subject string to it.
   *  The Matcher will do the actual searching, replacing or splitting.<p>
   *
   *  You can create as many Matcher objects from a single Pattern object
   *  as you want, and use the Matchers at the same time.  To apply the regex
   *  to another subject string, either create a new Matcher using
   *  compiledRegex.matcher() or tell the existing Matcher to work on a new
   *  string by calling regexMatcher.reset(subjectString).
   */
  void btnObjects_actionPerformed(ActionEvent e) {
    compiledRegex = null;
    textReplaceResults.setText("n/a");
    try {
      // If you do not want to specify any options (this is the case when
      // all checkboxes in this demo are unchecked), you can omit the
      // second parameter for the Pattern.compile() class factory.
      compiledRegex = Pattern.compile(textRegex.getText(), getRegexOptions());
      // Create the object that will search the subject string
      // using the regular expression.
      regexMatcher = compiledRegex.matcher(textSubject.getText());
      textResults.setText("Pattern and Matcher objects created.");
    } catch (PatternSyntaxException ex) {
      // textRegex does not contain a valid regular expression
      textResults.setText("You have an error in your regular expression:\n" +
                          ex.getDescription());
    } catch (IllegalArgumentException ex) {
      // This exception indicates a bug in getRegexOptions
      textResults.setText("Undefined bit values are set in the regex options");
    }
  }

  /** Print the results of a search produced by regexMatcher.find()
   *  and stored in regexMatcher.
   */
  void printMatch() {
    try {
      textResults.setText("Index of the first character in the match: " +
                          Integer.toString(regexMatcher.start()) + "\n");
      textResults.append("Index of the first character after the match: " +
                         Integer.toString(regexMatcher.end()) + "\n");
      textResults.append("Length of the match: " +
                         Integer.toString(regexMatcher.end() - 
                                          regexMatcher.start()) + "\n");
      textResults.append("Matched text: " + regexMatcher.group() + "\n");
      if (regexMatcher.groupCount() > 0) {
        // Capturing parentheses are numbered 1..groupCount()
        // group number zero is the entire regex match
        for (int i = 1; i <= regexMatcher.groupCount(); i++) {
          String groupLabel = new String("Group " + Integer.toString(i));
          if (regexMatcher.start(i) < 0) {
            textResults.append(groupLabel + 
                               " did not participate in the overall match\n");
          } else {
            textResults.append(groupLabel + " start: " +
                               Integer.toString(regexMatcher.start(i)) + "\n");
            textResults.append(groupLabel + " end: " +
                               Integer.toString(regexMatcher.end(i)) + "\n");
            textResults.append(groupLabel + " length: " +
                               Integer.toString(regexMatcher.end(i) -
                                                regexMatcher.start(i)) + "\n");
            textResults.append(groupLabel + " matched text: " + 
                               regexMatcher.group(i) + "\n");
          }
        }
      }
    } catch (IllegalStateException ex) {
      // Querying the results of a Matcher object before calling find()
      // or after a call to find() returned False, throws an IllegalStateException
      // This indicates a bug in our application
      textResults.setText("Cannot print match results if there aren't any");
    } catch (IndexOutOfBoundsException ex) {
      // Querying the results of groups (capturing parentheses or backreferences)
      // that do not exist throws an IndexOutOfBoundsException
      // This indicates a bug in our application
      textResults.setText("Cannot print match results of non-existent groups");
    }
  }

  /** Finds the first match if this is the first search, or if the previous search
   *  came up empty. Otherwise, it finds the next match after the previous match.
   *
   *  Note that even if you typed in new text for the regex or subject,
   *  btnNextMatch uses the subject and regex as they were when you clicked
   *  btnCreateObjects.
   */
  void btnNextMatch_actionPerformed(ActionEvent e) {
    textReplaceResults.setText("n/a");
    if (regexMatcher == null) {
      textResults.setText("Click Create Objects to create the Matcher object");
    } else {
      // Caling Matcher.find() without any parameters continues the search at
      // Matcher.end().  Starts from the beginning of the string if this is 
      // the first search using the Matcher or if the previous search 
      // did not find any (further) matches.
      if (regexMatcher.find()) {
        printMatch();
      } else {
        // This also resets the starting position for find() 
        // to the start of the subject string
        textResults.setText("No further matches");
      }
    }
  }

  /** Perform a regular expression search-and-replace using a Matcher object.
   *  This is the recommended way if you often use the same regular expression
   *  to do a search-and-replace.  You should also reuse the Matcher object
   *  by calling Matcher.reset(nextSubjectString) for improved efficiency.<p>
   *
   *  You also need to use the Pattern and Matcher objects for the 
   *  search-and-replace if you want to use the regex options such as 
   *  "case insensitive" or "dot all".<p>
   *
   *  See the btnReplace notes for the special $-syntax in the replacement text.
   */
  void btnObjReplace_actionPerformed(ActionEvent e) {
    if (regexMatcher == null) {
      textResults.setText("Click Create Objects to create the Matcher object");
    } else {
      try {
        textReplaceResults.setText(regexMatcher.replaceAll(textReplace.getText()));
      } catch (IllegalArgumentException ex) {
        // textReplace contains inapropriate dollar signs
        textResults.setText("You have an error in the replacement text:\n" +
                            ex.getMessage());
        textReplaceResults.setText("n/a");
      } catch (IndexOutOfBoundsException ex) {
        // textReplace contains a backreference that does not exist
        // (e.g. $4 if there are only three groups)
        textResults.setText("Non-existent group in the replacement text:\n" +
                            ex.getMessage());
        textReplaceResults.setText("n/a");
      }
    }
  }

  /** Using Matcher.appendReplacement() and Matcher.appendTail() you can implement
   *  a search-and-replace of arbitrary complexity.  These routines allow you
   *  to compute the replacement string in your own code.  So the replacement text
   *  can be whatever you want.<p>
   *
   *  To do this, simply call Matcher.find() in a loop.  For each match returned
   *  by find(), call appendReplacement() with whatever replacement text you want.
   *  When find() can no longer find matches, call appendTail().<p>
   *
   *  appendReplacement() appends the substring between the end of the previous
   *  match that was replaced with appendReplacement() and the current match.  
   *  If this is the first call to appendReplacement() since creating the Matcher
   *  or calling reset(), then the appended substring starts at the start of 
   *  the string.  Then, the specified replacement text is appended.  
   *  If the replacement text contains dollar signs, they will be interpreted 
   *  as usual.  E.g. $1 is replaced with the match between the first pair of 
   *  capturing parentheses.<p>
   *
   *  appendTail() appends the substring between the end of the previous match
   *  that was replaceced with appendReplacement() and the end of the string.
   *  If appendReplacement() was not called since creating the Matcher or 
   *  calling reset(), the entire subject string is appended.<p>
   *
   *  The above means that you should call Matcher.reset() before starting the
   *  operation, unless you're sure the Matcher is freshly constructed.
   *  If certain matches do not need to be replaced, simply skip calling 
   *  appendReplacement() for those matches. (Calling appendReplacement() with 
   *  Matcher.group() as the replacement text will only hurt performance and 
   *  may get you into trouble with dollar signs that may appear in the match.)
   */
  void btnAdvancedReplace_actionPerformed(ActionEvent e) {
    if (regexMatcher == null) {
      textResults.setText("Click Create Objects to create the Matcher object");
    } else {
      // We will store the replacement text here
      StringBuffer replaceResult = new StringBuffer();
      while (regexMatcher.find()) {
        try {
          // In this example, we simply replace the regex match with the same text
          // in uppercase.  Note that appendReplacement parses the replacement 
          // text to substitute $1, $2, etc. with the contents of the 
          // corresponding capturing parentheses just like replaceAll()
          regexMatcher.appendReplacement(replaceResult, 
                                         regexMatcher.group().toUpperCase());
        } catch (IllegalStateException ex) {
          // appendReplacement() was called without a prior successful call to find()
          // This exception indicates a bug in your source code
          textResults.setText("appendReplacement() called without a prior" +
                              "successful call to find()");
          textReplaceResults.setText("n/a");
          return;
        } catch (IllegalArgumentException ex) {
          // Replacement text contains inapropriate dollar signs
          textResults.setText("Error in the replacement text:\n" +
                              ex.getMessage());
          textReplaceResults.setText("n/a");
          return;
        } catch (IndexOutOfBoundsException ex) {
          // Replacement text contains a backreference that does not exist
          // (e.g. $4 if there are only three groups)
          textResults.setText("Non-existent group in the replacement text:\n" +
                              ex.getMessage());
          textReplaceResults.setText("n/a");
          return;
        }
      }
      regexMatcher.appendTail(replaceResult);
      textReplaceResults.setText(replaceResult.toString());
      textResults.setText("n/a");
      // After using appendReplacement and appendTail, the Matcher object must be 
      // reset so we can use appendReplacement and appendTail again.
      // In practice, you will probably put this call at the start of the routine
      // where you want to use appendReplacement and appendTail.
      // I did not do that here because this way you can click on the Next Match
      // button a couple of times to skip a few matches, and then click on the
      // Advanced Replace button to observe that appendReplace() will copy the
      // skipped matches unchanged.
      regexMatcher.reset();
    }
  }

  /** If you want to split many strings using the same regular expression,
   *  you should create a Pattern object and call Pattern.split()
   *  rather than String.split().  Both methods produce exactly the same results.
   *  However, when creating a Pattern object, you can specify options such as
   *  "case insensitive" and "dot all".<p>
   *
   *  Note that no Matcher object is used.
   */
  void btnObjSplit_actionPerformed(ActionEvent e) {
    textReplaceResults.setText("n/a");
    if (compiledRegex == null) {
      textResults.setText("Please click Create Objects to compile the regex");
    } else {
      printSplitArray(compiledRegex.split(textSubject.getText() /*, Limit*/));
    }
  }
}

// ActionListener classes generated by JBuilder 9 have been omitted for brevity
RegexBuddy Get RegexBuddy and easily use the power of regular expressions in Java.

Tutorial | Tools & Languages | Examples | Books & Reference |

grep | PowerGREP | RegexBuddy | RegexMagic |

EditPad Pro |

Delphi | GNU (Linux) | Groovy | Java | JavaScript | .NET | PCRE (C/C++) | Perl | PHP | POSIX | PowerShell | Python | R | REALbasic | Ruby | Tcl | VBScript | Visual Basic 6 | wxWidgets | XML Schema | XQuery & XPath |

MySQL | Oracle | PostgreSQL |