メッセージテンプレートをユーザーが送信しようとしているメッセージと一致させるアプリケーションを作成しようとしています。メッセージの照合にJava正規表現を使用しています。テンプレート/メッセージには特殊文字が含まれている場合があります。
正規表現が機能し、可能な限り最大の場合に一致するためにエスケープする必要がある特殊文字の完全なリストを取得するにはどうすればよいですか?
Java正規表現のすべての特殊文字をエスケープするためのユニバーサルソリューションはありますか?
Patternクラスのjavadocを見ることができます:http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html
特別な意味ではなく通常の文字が必要な場合は、そこにリストされている文字をエスケープする必要があります。
おそらくもっと簡単な解決策として、テンプレートを\Qと\Eの間に置くことができます-それらの間のすべてはエスケープされていると見なされます。
\.[]{}()<>*+-=!?^$|
]
および}
)は、同じタイプの括弧を開いた後にのみエスケープする必要があります。[]
括弧内の一部の文字(+
およびなど-
)は、エスケープなしで機能する場合があります。文字列リテラル/メタ文字のドキュメントページによると、次のとおりです。
<([{\^-=$!|]})?*+.>
また、そのリストをコードのどこかで参照するのはクールですが、それがどこにあるのかわかりません...
誰もが言ったことを組み合わせて、正規表現に固有の文字のリストを独自の文字列に明確にリストし、何千もの「\\」を視覚的に解析しようとする必要をなくすために、次のことを提案します。これは私にとってはかなりうまくいくようです:
final String regExSpecialChars = "<([{\\^-=$!|]})?*+.>";
final String regExSpecialCharsRE = regExSpecialChars.replaceAll( ".", "\\\\$0");
final Pattern reCharsREP = Pattern.compile( "[" + regExSpecialCharsRE + "]");
String quoteRegExSpecialChars( String s)
{
Matcher m = reCharsREP.matcher( s);
return m.replaceAll( "\\\\$0");
}
答えはJavaに対するものですが、コードは私が思いついたこのKotlin String拡張機能から簡単に適応できます(提供された@brcolowから適応):
private val escapeChars = charArrayOf(
'<',
'(',
'[',
'{',
'\\',
'^',
'-',
'=',
'$',
'!',
'|',
']',
'}',
')',
'?',
'*',
'+',
'.',
'>'
)
fun String.escapePattern(): String {
return this.fold("") {
acc, chr ->
acc + if (escapeChars.contains(chr)) "\\$chr" else "$chr"
}
}
fun main() {
println("(.*)".escapePattern())
}
プリント\(\.\*\)
ここで実際に確認してくださいhttps://pl.kotl.in/h-3mXZkNE
@SorinによるJavaパターンドキュメントの提案では、エスケープする文字は少なくとも次のように見えます。
\.[{(*+?^$|
Pattern.quote(String s)
ある種はあなたが望むことをします。ただし、それはまだ少し残っています。実際には個々の文字をエスケープするのではなく、文字列を。でラップするだけ\Q...\E
です。
探していることを正確に実行する方法はありませんが、幸いなことに、Java正規表現のすべての特殊文字をエスケープするのは実際にはかなり簡単です。
regex.replaceAll("[\\W]", "\\\\$0")
なぜこれが機能するのですか?のドキュメントには、Pattern
必ずしもエスケープする必要のないアルファベット以外の文字をエスケープすることが許可されていると具体的に記載されています。
エスケープされた構成を示さない英字の前に円記号を使用するとエラーになります。これらは、正規表現言語の将来の拡張のために予約されています。非アルファベット文字がエスケープされていない構成の一部であるかどうかに関係なく、その文字の前に円記号を使用できます。
たとえば、;
は正規表現の特殊文字ではありません。ただし、エスケープすると、Pattern
はとして解釈\;
され;
ます。さらにいくつかの例を示します。
>
\>
に相当するものになります>
[
\[
のエスケープされた形式になります[
8
まだ8
です。\)
\\\)
のエスケープされた形式\
と(
連結されたものになります。注:重要なのは「非アルファベット」の定義です。これは、ドキュメントでは実際には「非単語」文字、または文字セット外の文字を意味し[a-zA-Z_0-9]
ます。
コインの反対側では、特殊文字= allChars --number --ABC --spaceをアプリのコンテキストで使用する場合、次のような「non-char」正規表現を使用する必要があります。
String regepx = "[^\\s\\w]*";
Java正規表現が使用するエスケープ文字のリストを持っていて信頼していると仮定すると(これらの文字がPatternクラスのメンバーで公開されていると便利です)、本当に必要な場合は、次のメソッドを使用して文字をエスケープできます。
private static final char[] escapeChars = { '<', '(', '[', '{', '\\', '^', '-', '=', '$', '!', '|', ']', '}', ')', '?', '*', '+', '.', '>' };
private static String regexEscape(char character) {
for (char escapeChar : escapeChars) {
if (character == escapeChar) {
return "\\" + character;
}
}
return String.valueOf(character);
}