Regex to match phone numbers, with comments Regular expressions are one of the worst aspects of debugging hell. Since they are contained in string literals, It's hard to comment how they work when the expressions are fairly long.

I have the following regular expression:

\b\d{3}[-.]?\d{3}[-.]?\d{4}\b


Source: RegExr.com

I commented it like this:

import java.util.regex.Pattern;

public class Main {
    public static void main(String[] args) {
        String regexStr = "";

        regexStr += "\\b";     //Begin match at the word boundary(whitespace boundary)
        regexStr += "\\d{3}";  //Match three digits
        regexStr += "[-.]?";   //Optional - Match dash or dot
        regexStr += "\\d{3}";  //Match three digits
        regexStr += "[-.]?";   //Optional - Match dash or dot
        regexStr += "\\d{4}";  //Match four digits
        regexStr += "\\b";     //End match at the word boundary(whitespace boundary)

        if (args[0].matches(regexStr)) {
            System.out.println("Match!");
        } else {
            System.out.println("No match.");
        }
    }
}


What would be the best way to go about commenting regular expressions to make them readable for beginners? Is there a better way than what I have shown?
Whatever you do, don't append strings like that!  If you look at the generated bytecode, you'll see that the compiler does exactly what you told it to do:

$ javap -c Main
Compiled from "Main.java"
public class Main {
  public Main();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."&lt;init&gt;":()V
       4: return        

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String 
       2: astore_1      
       3: new           #3                  // class java/lang/StringBuilder
       6: dup           
       7: invokespecial #4                  // Method java/lang/StringBuilder."&lt;init&gt;":()V
      10: aload_1       
      11: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      14: ldc           #6                  // String \b
      16: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      19: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      22: astore_1      
      23: new           #3                  // class java/lang/StringBuilder
      26: dup           
      27: invokespecial #4                  // Method java/lang/StringBuilder."&lt;init&gt;":()V
      30: aload_1       
      31: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      34: ldc           #8                  // String \d{3}
      36: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      39: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      42: astore_1      
      43: new           #3                  // class java/lang/StringBuilder
      46: dup           
      47: invokespecial #4                  // Method java/lang/StringBuilder."&lt;init&gt;":()V
      50: aload_1       
      51: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      54: ldc           #9                  // String [-.]?
      56: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      59: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      62: astore_1      
      63: new           #3                  // class java/lang/StringBuilder
      66: dup           
      67: invokespecial #4                  // Method java/lang/StringBuilder."&lt;init&gt;":()V
      70: aload_1       
      71: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      74: ldc           #8                  // String \d{3}
      76: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      79: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      82: astore_1      
      83: new           #3                  // class java/lang/StringBuilder
      86: dup           
      87: invokespecial #4                  // Method java/lang/StringBuilder."&lt;init&gt;":()V
      90: aload_1       
      91: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      94: ldc           #9                  // String [-.]?
      96: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      99: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     102: astore_1      
     103: new           #3                  // class java/lang/StringBuilder
     106: dup           
     107: invokespecial #4                  // Method java/lang/StringBuilder."&lt;init&gt;":()V
     110: aload_1       
     111: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     114: ldc           #10                 // String \d{4}
     116: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     119: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     122: astore_1      
     123: new           #3                  // class java/lang/StringBuilder
     126: dup           
     127: invokespecial #4                  // Method java/lang/StringBuilder."&lt;init&gt;":()V
     130: aload_1       
     131: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     134: ldc           #6                  // String \b
     136: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     139: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     142: astore_1      
     143: aload_0       
     144: iconst_0      
     145: aaload        
     146: aload_1       
     147: invokevirtual #11                 // Method java/lang/String.matches:(Ljava/lang/String;)Z
     150: ifeq          164
     153: getstatic     #12                 // Field java/lang/System.out:Ljava/io/PrintStream;
     156: ldc           #13                 // String Match!
     158: invokevirtual #14                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     161: goto          172
     164: getstatic     #12                 // Field java/lang/System.out:Ljava/io/PrintStream;
     167: ldc           #15                 // String No match.
     169: invokevirtual #14                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     172: return        
}


If you change it to concatenate all the string literals in one statement…

public class Main {
    public static void main(String[] args) {
        String regexStr =
            "\\b" +      //Begin match at the word boundary(whitespace boundary)
            "\\d{3}" +   //Match three digits
            "[-.]?" +    //Optional - Match dash or dot
            "\\d{3}" +   //Match three digits
            "[-.]?" +    //Optional - Match dash or dot
            "\\d{4}" +   //Match four digits
            "\\b";       //End match at the word boundary(whitespace boundary)

        if (args[0].matches(regexStr)) {
            System.out.println("Match!");
        } else {
            System.out.println("No match.");
        }
    }
}


Then the bytecode is much saner (one literal string at offset 0):

$ javap -c Main
Compiled from "Main.java"
public class Main {
  public Main();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."&lt;init&gt;":()V
       4: return        

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String \b\d{3}[-.]?\d{3}[-.]?\d{4}\b
       2: astore_1      
       3: aload_0       
       4: iconst_0      
       5: aaload        
       6: aload_1       
       7: invokevirtual #3                  // Method java/lang/String.matches:(Ljava/lang/String;)Z
      10: ifeq          24
      13: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
      16: ldc           #5                  // String Match!
      18: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      21: goto          32
      24: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
      27: ldc           #7                  // String No match.
      29: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      32: return        
}