0

HTML 文字として現れる可能性のあるセミコロンを無視して、セミコロンで文字列を分割する必要があります。たとえば、次の文字列があるとします。

id=com.google.android;keywords=Android&#59;Operating System&#59;Phone;versions=Gingerbread&#59;ICS&#59;JB

次のように分割する必要があります。

id = com.google.android
keywords=Android&#59;Operating System&#59;Phone
versions=Gingerbread&#59;ICS&#59;JB

これを行う方法はありますか?

4

2 に答える 2

3

のような正規表現(?<!&#?[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));
}
于 2013-01-18T15:00:53.330 に答える
0

HTML エンティティでは、'&#' と ';' の間に 2 つまたは 3 つの数字しかないため、次の正規表現を使用しました。

(?<!&#\d{2,3});
于 2013-01-18T20:06:39.713 に答える