37
34

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Java】正規表現のまとめ

Last updated at Posted at 2020-10-31

一覧

パターン マッチ文字列
XYZ XYZという文字列
[XYZ] XYZいずれか一文字
[^XYZ] XYZ以外の一文字
[X-Z] X~Yの範囲で一文字
[a-zA-Z] aからz、またはA~Zの範囲
(X|Y|Z) XYZのいずれか
[ABC|]
X* Xが0回以上発生
("do*n"の場合"dn","don","dooon"など)
X+ Xが1回以上発生
("do+n"の場合"don","dooon"など)
X? Xが0または1回発生
("do?n"の場合"dn"か"don")
X{n} Xがn回発生
("do{2}n"の場合"doon")
X{n,} Xがn回以上発生
("do{2,}n"の場合"doon","doooon"など)
X{n,m} Xがn~m回発生
("do{2,3}n"の場合"doon"か"dooon")
. 任意の文字
\w 大文字/小文字の英数字、アンダースコア
[a-zA-Z_0-9]
\d 数字
[0-9]
\D 数字以外
[^0-9]
\s 空白
[ \t\n\x0B\f\r]
^ 行先頭一致
$ 行末尾一致
\b 単語境界
\|バックスラッシュに一致
\n 改行文字に一致
\t タブ文字に一致
^\d{10}$ 半角数値10桁
^\d{5,10}$ 半角数値5桁以上10桁以下
\d{2,4}-\d{2,4}-\d{4} 電話番号
(半角数値2~3桁-半角数値2~3桁-半角数値4桁)
^\d{3}-\d{4}$ 郵便番号
(半角数値3桁-半角数値4桁)
^[0-9a-zA-Z]+$ 1桁以上の半角英数
(0-9、a-z、A-Z)

###電話/郵便番号一致サンプル

//サンプル1 電話/郵便番号一致
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {
 public static void main(String[] args) {
    //判定する文字列
    String str = "012-345-6789";
    //判定するパターンを生成
    Pattern p = Pattern.compile("\\d{2,4}-\\d{2,4}-\\d{4}"); //電話番号
    //Pattern p = Pattern.compile("^\\d{3}-\\d{4}$"); //郵便番号
    Matcher m = p.matcher(str);

    System.out.println(m.find()); //true
    }
}

###前方/後方/部分一致サンプル

//サンプル2 前方/後方/部分一致
public class Main {
 public static void main(String[] args) {
    //判定する文字列
    String str = "000012-345-6789";
    //判定するパターンを生成
    //Pattern p = Pattern.compile("\\d{2,4}-\\d{2,4}-\\d{4}.*"); //電話番号前方一致
    //Pattern p = Pattern.compile(".*\\d{2,4}-\\d{2,4}-\\d{4}"); //電話番号後方一致
    Pattern p = Pattern.compile(".*\\d{2,4}-\\d{2,4}-\\d{4}.*"); //電話番号部分一致
    Matcher m = p.matcher(str);

    System.out.println(m.find()); //true
    }
}

#マッチした文字列を抜き出す

  • PatternクラスのcompileメソッドでPatternオブジェクト準備
  • matcherメソッドで文字列検索を行うMacherオブジェクト生成
  • while (match.find())でfindメソッドがfalseになるまでマッチング繰り返し、文字列の開始位置(start)、終了位置(end)、マッチ文字列(group)を取得
    • group[0]:マッチした文字列全体
    • group[1]:サブマッチ文字列1番目の要素
import java.util.*;
import java.util.regex.Pattern;

public class Main {
  public static void main(String[] args) {
    var str = "携帯は0123-99-0000です。自宅は000-123-4567やで。";
    var ptn = Pattern.compile("(\\d{2,4})-(\\d{2,4})-(\\d{4})");
    var match = ptn.matcher(str);
    while (match.find()) {
      System.out.println("開始位置:" + match.start());
      System.out.println("終了位置:" + match.end());
      System.out.println("マッチング文字列:" + match.group());
      System.out.println("市外局番:" + match.group(1));
      System.out.println("市内局番:" + match.group(2));
      System.out.println("加入者番号:" + match.group(3));
      System.out.println("-----");
    }
  }
}

#マッチング時の挙動制御

  • マッチフラグでPatternクラスをインスタンス化する時の挙動を変更できる

##CASE_INSENSITIVE

  • 大文字小文字区別しない
import java.util.*;
import java.util.regex.Pattern;

public class Main {
  public static void main(String[] args) {
    var str = "仕事用はneko@example.comです。プライベート用はNEKO@example.comです。";
    var ptn = Pattern.compile("[a-z0-9.!#$%&'*+/=?^_{|}~-]+@[a-z0-9-]+(\\.[a-z0-9-]+)*", Pattern.CASE_INSENSITIVE);
    var match = ptn.matcher(str);
    while (match.find()) {
      System.out.println(match.group());
    }
  }
}

#MULTILINE

  • ^$の挙動変更
  • ^は先頭のみではなく改行後の数字もマッチする
  • $の場合行末にもマッチ
import java.util.*;
import java.util.regex.Pattern;

public class Main {
  public static void main(String[] args) {
    var str = "1年生になったら友達\n100人できるかな\n";
    // var ptn = Pattern.compile("^\\d*");
    var ptn = Pattern.compile("^\\d*", Pattern.MULTILINE);
    var match = ptn.matcher(str);
    while (match.find()) {
      System.out.println(match.group()); //1 100
    }
  }
}

##DOTALL
* .の挙動変更
* 改行(\n)も含んだ全部の文字列にマッチ
* 文字列を単一の行としてマッチできる(シングルラインモード)

import java.util.*;
import java.util.regex.Pattern;

public class Main {
  public static void main(String[] args) {
    var str = "会いたかった\n会いたかった\n会いたかった\nYES";
    // var ptn = Pattern.compile("^.+");
    var ptn = Pattern.compile("^.+", Pattern.DOTALL);
    var match = ptn.matcher(str);
    while (match.find()) {
      System.out.println(match.group());
      //会いたかった
      //会いたかった
      //会いたかった
      //YES
    }
  }
}

#埋め込みフラグ

  • 以下コードは同じ
    • ?i :CASE_INSENSITIVE
    • ?m :MULTILINE
    • ?s :DOTALL
    • ?u :UNICODE_CASE
    • ?d :UNIX_LINES
    • ?x :COMMENTS
var ptn = Pattern.compile("(?i)[a-z0-9.!#$%&'*+/=?^_{|}~-]+@[a-z0-9-]+(\\.[a-z0-9-]+)*");

//var ptn = Pattern.compile("[a-z0-9.!#$%&'*+/=?^_{|}~-]+@[a-z0-9-]+(\\.[a-z0-9-]+)*", Pattern.CASE_INSENSITIVE);

#最長一致・最短一致

  • <.+> 最長一致(出来るだけ長い文字列を一致)
    • <...>のなかに.(任意の文字)が+(1文字以上)
    • 全部のタグ文字が出力
  • <.+?> 最短一致(出来るだけ短い文字列を一致)
    • 個々のタグ文字が一個ずつ出力
import java.util.regex.Pattern;

public class Main {
  public static void main(String[] args) {
    var tags = "<p><strong>NEKO</strong>サイト<a href='index.html'><img src='cat.jpg' /></a></p>";
    //最長一致
    //var ptn = Pattern.compile("<.+>"); //<p><strong>NEKO</strong>サイト<a href='index.html'><img src='cat.jpg' /></a></p>
    //最短一致
    var ptn = Pattern.compile("<.+?>");
    var match = ptn.matcher(tags);
    while (match.find()) {
      System.out.println(match.group());
      //<p>
      //<strong>
      //</strong>
      //<a href='index.html'>
      //<img src='cat.jpg' />
      //</a>
      //</p>
    }
  }
}

#名前付きキャプチャ

  • groupに名前をつけてキャプチャ
  • group("名前")でアクセス
import java.util.regex.Pattern;

public class Main {
  public static void main(String[] args) {
    var msg = "携帯は0123-99-0000です。自宅は000-123-4567やで。";
    var ptn = Pattern.compile("(?<area>\\d{2,4})-(?<city>\\d{2,4})-(?<local>\\d{4})");
    var match = ptn.matcher(msg);
    while (match.find()) {
      System.out.println("開始位置:" + match.start());
      System.out.println("終了位置:" + match.end());
      System.out.println("マッチング文字列:" + match.group());
      System.out.println("市外局番:" + match.group("area"));
      System.out.println("市内局番:" + match.group("city"));
      System.out.println("加入者番号:" + match.group("local"));
      System.out.println("-----");
    }
  }
}

#後方参照

  • マッチした文字列を\\1で後から参照できる
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class Main {
  //後方参照
  public static void main(String args[]){
    String str1 = "My name is <div>Neko</div>";
    String str2 = "I am a <span>Cat</span>";
    String str3 = "<span>Hello World</div>";
    String regex = "<(div|span)>.*?<\\/\\1>";
    Pattern p = Pattern.compile(regex);
    System.out.println("パターン : " + regex);
    check(p, str1);
    check(p, str2);
    check(p, str3);
  }
  private static void check(Pattern p, String target){
    Matcher m = p.matcher(target);

    if (m.find()){
      System.out.println("Match! " + target);
    }else{
      System.out.println("Unmatch! " + target);
    }
  }
}

#先読み・後読み

  • 前後の文字列の有無でマッチするか判定
    • A(?=B) :Aの直後にBが続く場合のみAにマッチ
    • A(?!B) :Aの直後にBが続かない場合のみAにマッチ
    • (?<=B)A :Aの直前にBがある場合のみAにマッチ
    • (?<!B)A :Aの直前にBがない場合のみAにマッチ
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class Main {

  private static void match(Pattern ptn, String input) {
    var match = ptn.matcher(input);
    while (match.find()) {
      System.out.println(match.group());
    }
    System.out.println("---");
  }

  public static void main(String[] args) {
    var re1 = Pattern.compile("わが(?=はい)"); 
    var re2 = Pattern.compile("わが(?!はい)"); 
    var re3 = Pattern.compile("(?<=。)わが");  
    var re4 = Pattern.compile("(?<!。)わが"); 
    var msg1 = "わがはいはねこである";        
    var msg2 = "わが輩はねこである。わがわがなまえはまだない。";
    match(re1, msg1); //わが
    match(re1, msg2); //---
    match(re2, msg1); //---
    match(re2, msg2); //わが,わが,わが
    match(re3, msg1); //---
    match(re3, msg2); //わが
    match(re4, msg1); //わが
    match(re4, msg2); //わが,わが
  }
}

#文字列置換

  • replaceAllメソッド
  • 置き換え後の文字列に置き換え前の文字列を含めることができる
    • $0 マッチ文字列全体
    • $1 サブマッチ文字列一番目
    • ${"名前"}で名前付きチャプチャグループ使用可能
  • replaceFirstメソッド:最初の文字列のみ置換
    • replaceメソッド:固定文字列の置換
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class Main {

  public static void main(String[] args) {
    var str = "お問い合わせはこちら https://www.neko.com/です。";
    System.out.println(str.replaceAll(
        "(?i)http(s)?://([\\w-]+\\.)+[\\w-]+(/[\\\\w ./?%&=-]*)?",
        "<a href=\"$0\">$0</a>"));
     //お問い合わせはこちら <a href="https://www.neko.com/">https://www.neko.com/</a>です。
  }
}

#文字列分割

  • splitメソッド
    • cf:strigクラスのsplitは正規表現をその都度コンパイルする
    • 同じパターンを再利用する時はPatternクラスを使う
import java.util.regex.Pattern;
public class Main {
  //一桁以上数字+わ で分割
  public static void main(String[] args) {
    var str = "にわには2わうらにわには22わにわとりがいる";
    var re = Pattern.compile("\\d{1,}わ");
    var result = re.split(str);
    System.out.println(String.join(" ", result)); 
    //にわには うらにわには にわとりがいる
  }
}
37
34
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
37
34

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?