一覧
パターン | マッチ文字列 |
---|---|
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));
//にわには うらにわには にわとりがいる
}
}