用正则表达式处理 HTML 标签是有问题的;如果可能的话,应该使用 HTML 解析。让我们举一个识别(虚构)标签<a> 和<b> 的简单案例。为了简单起见,我们假设我们不必担心这些标签或空白区域的属性。我们有兴趣识别嵌套在<a> 标记中的单个<b> 标记,例如:
<a><b>1</b></a>
“明显”但不正确的正则表达式是:
<a><b>.*?</b></a>
它会匹配上面的例子,但它也会匹配:
<a><b>1</b><b>2</b></a>
即使.*? 不是贪心,它也是贪婪的,它试图将输入的其余部分与正则表达式的其余部分进行匹配。
您需要将 .*? 替换为不会扫描结束 </b> 标记的内容:
((?!</b>).)*
这表示只要下一个字符不是结束 </b> 标记,就再扫描一个字符。为了更好地衡量,您可能还需要确保不要跳过另一个 <a> 标记的开头:
((?!(<a>|</b>)).)*
所以最终的正则表达式变为:
<a><b>((?!(<a>|</b>)).)*</b></a>
无论如何,这就是我所采取的方法。因此,当前问题的正则表达式变得相当复杂。
我的理解是,您正在寻找一个带有两个嵌套 <td> 标记的 <tr> 标记,然后是 0 个或多个 <tr> 标记和一个嵌套 <td> 标记。如果我直截了当,那么正则表达式是:
"(?s)<tr[^>]*>(\\s*<td[^>]*>((?!(<tr|</td)).)*</td>\\s*){2}\\s*</tr>(\\s*<tr[^>]*>\\s*<td[^>]*>((?!(<tr|</td)).)*</td>\\s*</tr>)*"
代码:
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.regex.MatchResult;
public class Test
{
public static void doMatch (String s) {
Pattern pattern = Pattern.compile("(?s)<tr[^>]*>(\\s*<td[^>]*>((?!(<tr|</td)).)*</td>\\s*){2}\\s*</tr>(\\s*<tr[^>]*>\\s*<td[^>]*>((?!(<tr|</td)).)*</td>\\s*</tr>)*");
Matcher matcher = pattern.matcher(s);
while (matcher.find()) {
MatchResult m = matcher.toMatchResult();
System.out.println("Match: " + m.group(0));
}
}
public static void main(String[] args) {
String s = "<tr>\n <td>XYZ</td>\n <td><tag1>abc\ndef</tag2></td>\n</tr>\n<tr>\n <td>XYZ</td>\n</tr>\n<tr>\n <td>XYZ</td>\n</tr>";
Test.doMatch(s);
s = "<tr><td>1></td><td>2</td></tr><tr><td>3></td><td>4</td></tr><tr><td>5></td><td>6</td></tr><tr><td>7</td></tr>";
Test.doMatch(s);
}
}
打印:
Match: <tr>
<td>XYZ</td>
<td><tag1>abc
def</tag2></td>
</tr>
<tr>
<td>XYZ</td>
</tr>
<tr>
<td>XYZ</td>
</tr>
Match: <tr><td>1></td><td>2</td></tr>
Match: <tr><td>3></td><td>4</td></tr>
Match: <tr><td>5></td><td>6</td></tr><tr><td>7</td></tr>