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]+(即&符号、可选哈希和一个或多个字母数字)。但是,lookbehinds 必须对它们可以匹配的字符数有一个上限,而这+没有,因此您必须使用有界重复计数,{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 实体在 '&#' 和 ';' 之间只有两个或三个数字 我使用了以下正则表达式:

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