のような正規表現(?<!&#?[0-9a-zA-Z]+);
はおそらくそれを行うでしょう。&#foo;
これにより、エンティティ参照または文字参照を終了するセミコロンとの一致が防止されますが、技術的に仕様のどちらにも当てはまらないいくつかのケースも検出されます (たとえば、 orの末尾のセミコロンとは一致しません&123;
)。
(?<!...)
は「否定後読み」であるため、この正規表現は、一致する部分文字列&#?[0-9a-zA-Z]+
(つまり、アンパサンド、オプションのハッシュ、および 1 つ以上の英数字) が前にないセミコロンに一致するものとして読み取ることができます。ただし、後読みには、一致できる文字数の上限が必要ですが、これはあり+
ません。そのため{1,5}
、 unbounded ではなく、制限付きの繰り返し回数を使用する必要があります+
。上限は、少なくとも表示される可能性のあるエンティティ参照と同じ長さである必要があり、データに任意のエンティティ参照が含まれている可能性がある場合は、文字列の長さなどを上限として使用する必要があります。
String[] keyValuePairs = theString.split(
"(?<!&#?[0-9a-zA-Z]{1," + theString.length() + "});");
より小さな境界を指定できる場合は、おそらくより効率的です。
編集: Android はどうやらこの後読みを好まないようです。制限付きの繰り返しであっても、おそらく単一の正規表現を使用して目的のString.split
処理を行うことはできません。たとえば、自分でループを実行する必要があります。
Pattern p = Pattern.compile("(?:&#?[0-9a-zA-Z]+)?;");
Matcher m = p.matcher(theString);
List<String> splits = new ArrayList<String>();
int lastEltStart = 0;
while(m.find()) {
if(m.end() - m.start() > 1) {
// this match was an entity/character reference so don't split here
continue;
}
if(m.start() > lastEltStart) {
// non-empty part
splits.add(theString.substring(lastEltStart, m.start()));
}
lastEltStart = m.end();
}
if(lastEltStart < theString.length()) {
// non-empty final part
splits.add(theString.substring(lastEltStart));
}