RegexpMultiline

Since Checkstyle 5.0

Description

Checks that a specified pattern matches across multiple lines in any file type.

Rationale: This check can be used to when the regular expression can be span multiple lines.

Properties

name description type default value since
fileExtensions Specify the file extensions of the files to process. String[] all files 5.0
format Specify the format of the regular expression to match. Pattern $. 5.0
ignoreCase Control whether to ignore case when searching. boolean false 5.0
matchAcrossLines Control whether to match expressions across multiple lines. boolean false 8.25
maximum Specify the maximum number of matches required in each file. int 0 5.0
message Specify the message which is used to notify about violations, if empty then default (hard-coded) message is used. String null 5.0
minimum Specify the minimum number of matches required in each file. int 0 5.0
reportGroup Specify which capturing group to use for violation reporting. int 0 13.3.0

Examples

To run the check with its default configuration (no matches will be):


<module name="Checker">
  <module name="RegexpMultiline"/>
</module>

Example:


class Example1 {
  void testMethod1() {

    System.out.print("Example");

    System.err.println("Example");
    System
    .out.print("Example");
    System
    .err.println("Example");
    System.
    out.print("Example");
    System.
    err.println("Example");
  }

  void testMethod2() {

    System.out.println("Test #1: this is a test string");

    System.out.println("TeSt #2: This is a test string");

    System.out.println("TEST #3: This is a test string");
    int i = 5;

    System.out.println("Value of i: " + i);

    System.out.println("Test #4: This is a test string");

    System.out.println("TEst #5: This is a test string");
  }
}

To configure the check to find calls to print to the console:


<module name="Checker">
  <module name="RegexpMultiline">
    <property name="format" value="System\.(out)|(err)\.print(ln)?\("/>
  </module>
</module>

Example:


class Example2 {
  void testMethod1() {
    // violation below, 'Line matches the illegal pattern'
    System.out.print("Example");
    // violation below, 'Line matches the illegal pattern'
    System.err.println("Example");
    System
      .out.print("Example");
    System
      .err.println("Example"); // violation, 'Line matches the illegal pattern'
    System.
      out.print("Example");
    System.
      err.println("Example"); // violation, 'Line matches the illegal pattern'
  }

  void testMethod2() {
    // violation below, 'Line matches the illegal pattern'
    System.out.println("Test #1: this is a test string");
    // violation below, 'Line matches the illegal pattern'
    System.out.println("TeSt #2: This is a test string");
    // violation below, 'Line matches the illegal pattern'
    System.out.println("TEST #3: This is a test string");
    int i = 5;
    // violation below, 'Line matches the illegal pattern'
    System.out.println("Value of i: " + i);
    // violation below, 'Line matches the illegal pattern'
    System.out.println("Test #4: This is a test string");
    // violation below, 'Line matches the illegal pattern'
    System.out.println("TEst #5: This is a test string");
  }
}

To configure the check to match text that spans multiple lines, like normal code in a Java file:


<module name="Checker">
  <module name="RegexpMultiline">
    <property name="matchAcrossLines" value="true"/>
    <property name="format" value="System\.out.*?print\("/>
  </module>
</module>

Example:


class Example3 {
  void testMethod1() {
    // violation below, 'Line matches the illegal pattern'
    System.out.print("Example");

    System.err.println("Example");
    System
    .out.print("Example");
    System
    .err.println("Example");
    System.
    out.print("Example");
    System.
    err.println("Example");
  }

  void testMethod2() {

    System.out.println("Test #1: this is a test string");

    System.out.println("TeSt #2: This is a test string");

    System.out.println("TEST #3: This is a test string");
    int i = 5;

    System.out.println("Value of i: " + i);

    System.out.println("Test #4: This is a test string");

    System.out.println("TEst #5: This is a test string");
  }
}

Note: Beware of the greedy regular expression used in the above example. .* will match as much as possible and not produce multiple violations in the file if multiple groups of lines could match the expression. To prevent an expression being too greedy, avoid overusing matching all text or allow it to be optional, like .*?. Changing the example expression to not be greedy will allow multiple violations in the example to be found in the same file.


To configure the check to match a maximum of three test strings:


<module name="Checker">
  <module name="RegexpMultiline">
    <property name="format" value="Test #[0-9]+:[A-Za-z ]+"/>
    <property name="ignoreCase" value="true"/>
    <property name="maximum" value="3"/>
  </module>
</module>

Example:


class Example4 {
  void testMethod1() {

    System.out.print("Example");

    System.err.println("Example");
    System
    .out.print("Example");
    System
    .err.println("Example");
    System.
    out.print("Example");
    System.
    err.println("Example");
  }

  void testMethod2() {

    System.out.println("Test #1: this is a test string");

    System.out.println("TeSt #2: This is a test string");

    System.out.println("TEST #3: This is a test string");
    int i = 5;

    System.out.println("Value of i: " + i);
    // violation below, 'Line matches the illegal pattern'
    System.out.println("Test #4: This is a test string");
    // violation below, 'Line matches the illegal pattern'
    System.out.println("TEst #5: This is a test string");
  }
}

To configure the check to match a minimum of two test strings:


<module name="Checker">
  <module name="RegexpMultiline">
    <property name="format" value="Test #[0-9]+:[A-Za-z ]+"/>
    <property name="minimum" value="2"/>
  </module>
</module>

Example:


class Example5 {
  void testMethod1() {

    System.out.print("Example");

    System.err.println("Example");
    System
    .out.print("Example");
    System
    .err.println("Example");
    System.
    out.print("Example");
    System.
    err.println("Example");
  }

  void testMethod2() {
    // violation below, 'Line matches the illegal pattern'
    System.out.println("Test #1: this is a test string");

    System.out.println("TEST #2: This is a test string");

    System.out.println("TEST #3: This is a test string");
    int i = 5;

    System.out.println("Value of i: " + i);
    // violation below, 'Line matches the illegal pattern'
    System.out.println("Test #3: This is a test string");
    // violation below, 'Line matches the illegal pattern'
    System.out.println("Test #4: This is a test string");
  }
}

To configure the check to restrict an empty file:


<module name="Checker">
  <module name="RegexpMultiline">
      <property name="format" value="^\s*$" />
      <property name="matchAcrossLines" value="true" />
      <property name="message" value="Empty file is not allowed" />
  </module>
</module>

Example of violation from the above config:


/var/tmp$ cat -n Test.java
1
2
3
4

Result:


/var/tmp/Test.java // violation, a file must not be empty.
        

To configure the check to detect test string patterns and report violations at the string content:


<module name="Checker">
  <module name="RegexpMultiline">
    <property name="format" value="Test #[0-9]+: ([A-Za-z ]+)"/>
    <property name="maximum" value="0"/>
    <property name="reportGroup" value="1"/>
  </module>
</module>

Example:


class Example7 {
  void testMethod1() {
    // violation below, 'Line matches the illegal pattern'
    System.out.println("Test #1: this is a test string");

    // violation below, 'Line matches the illegal pattern'
    System.out.println("Test #2: another test string");
  }
}

The pattern Test #[0-9]+: ([A-Za-z ]+) contains one capturing group. Setting reportGroup="1" reports violations at the test string content (group 1) instead of at the beginning of the entire match (which would include "Test #").


To configure the check to detect variable assignments and report violations at the numeric value:


<module name="Checker">
  <module name="RegexpMultiline">
    <property name="format" value="([A-Z]+) = ([0-9]+)"/>
    <property name="maximum" value="0"/>
    <property name="reportGroup" value="2"/>
  </module>
</module>

Example:


class Example8 {
  void testMethod1() {
    int A = 5; // violation, 'Line matches the illegal pattern'
    int B = 20; // violation, 'Line matches the illegal pattern'
    int C = 99; // violation, 'Line matches the illegal pattern'
  }
}

The pattern ([A-Z]+) = ([0-9]+) has two capturing groups. Setting reportGroup="2" reports violations at the numeric value (group 2) instead of at the variable name (group 1) or the entire match (group 0). This allows you to highlight the specific part of the pattern that needs attention.

Note: The reportGroup property specifies which capturing group to use for determining the line number where violations are reported. Group 0 represents the entire match, group 1 is the first capturing group, group 2 is the second, and so on. If reportGroup exceeds the number of groups in the pattern, the check falls back to reporting at the entire match.

Example of Usage

Violation Messages

All messages can be customized if the default message doesn't suit you. Please see the documentation to learn how to.

Package

com.puppycrawl.tools.checkstyle.checks.regexp

Parent Module

Checker