如何使模式有点清晰?

时间:2017-11-03 15:51:22

标签: java regex

我正在尝试使用regexp解析html页面,但我想编译的模式看起来像怪物。

public static void main(String[] args)  {
        String form = "123123" +
                "<input type=\"hidden\" name=\"ip_h\" value=\"8d25cea553b4afe087\" />\n" +
                "<input type=\"hidden\" name=\"lg_h\" value=\"e04c5b67874fd6e28b\" />\n" +
                "<input type=\"hidden\" name=\"_origin\" value=\"https://oauth.site.com\" />\n"+
                 "<input type=\"hidden\" name=\"to\" value=\"aHR0cHM6Ly9vYXV0aC52ay5jb20vYXl\" />";
        Pattern pattern = Pattern.compile(".*\"ip_h\".value=\"([a-z0-9]*)\".*\\s.*lg_h\".value=\"([a-z0-9]*)\".*\\s.*\\s.*to\".value=\"([a-zA-Z0-9]*)\".*");
        Matcher matcher = pattern.matcher(form);
        matcher.matches();
        System.out.println(matcher.group(1)+matcher.group(2)+matcher.group(3));

    }

有没有机会让它清楚一点? 为什么我应该总是使用\ s当我有“\ n”? (。*) - 是否也匹配所有内容和空格? 另外,如果我想获得有关错误的更多信息,我该怎么办,不仅:“线程中的异常”主“java.lang.IllegalStateException:找不到匹配项”

1 个答案:

答案 0 :(得分:0)

在我看来,我认为你只是为了完成手头的任务而过度思考你的正则表达式。保持表达式尽可能简单易读是一个好主意。很明显,你已经意识到了这一点。

此处显然需要分组,因为您只需要与该数据特定相关的名称中的特定数据。由于您已经知道名称,因此您希望从中获取特定数据会使事情变得更容易:

现在我不知道网页内容是由什么组成的,但我们将介绍几个场景。你的情况很可能是两者中的后者。

情景1:

如果网页内容中只有特定行数包含:

<input type="hidden" name="ip_h" value="8d25cea553b4afe087" />
<input type="hidden" name="lg_h" value="e04c5b67874fd6e28b" />
<input type="hidden" name="_origin" value="https://oauth.site.com" />
<input type="hidden" name="to" value="aHR0cHM6Ly9vYXV0aC52ay5jb20vYXl" />

并且名称总是以相同的顺序,然后您可以使用这样的简单正则表达式:

"value\\=\"(.*?)\""

与说法相同:

浏览整个字符串并将之间的所有字符串一个看起来像value="的子字符串和一个双引号字符()您想要的值是双引号

现在只需迭代找到的项目来收集数据:

while (matcher.find()) {
    System.out.println(matcher.group(1));
}

如果网页内容中还有其他行包含标题为value=且其值也在双引号内的行,那么这根本不会很好用。上面的正则表达式示例也会将数据拉出来,这显然是不行的。正则表达式不够具体,现在将我们带到下一个场景。

情景2:

在此特定情况下,网页内容包含许多行,这些行的标题为value=,其相关数据值在双引号内()。我们显然不会想要他们所有,所以我们需要更正确地使用我们的正则表达式。因为我们知道与内容中的名称键相关的名称我们如何尝试:

"(\"ip_h\"|\"lg_h\"|\"to\").*value\\=\"(.*?)\""

这里我们正在使用两个组,我们想要的实际数据将包含在第二组中。第一组使用RegEx OR运算符( | )来保持简单。上面的正则表达式基本上是说:

在整个字符串中工作,如果您遇到名称“ip_h”或名称“ip_h”或名称“到“和那个名称之后的某个地方是一个看起来像 value =”的子字符串然后抓住 value =“之间的数据和下一个遇到的双重数据引号并将其放入第2组。

现在只需迭代找到的项目来收集第2组中包含的数据:

while (matcher.find()) {
    System.out.println(matcher.group(2));
}

如果您发现仍需要更具体,以适应您的正则表达式。您可以添加另一个组。如果你发现它变大了,那么如果你愿意,可以将你的表达式放到一个String变量中。

String regEx = "(\\<input type\\=\"hidden\".*)(\"ip_h\"|\"lg_h\"|\"to\").*value\\=\"(.*?)\"";

Pattern pattern = Pattern.compile(regEx);
Matcher matcher = pattern.matcher(form);

// The required data ca be obtained from Group 3

以下是您稍微修改过的代码:

String form = "123123" +
        "<input type=\"hidden\" name=\"ip_h\" value=\"8d25cea553b4afe087\" />\n" +
        "<input type=\"hidden\" name=\"lg_h\" value=\"e04c5b67874fd6e28b\" />\n" +
        "<input type=\"hidden\" name=\"_origin\" value=\"https://oauth.site.com\" />\n"+
        "<input type=\"hidden\" name=\"to\" value=\"aHR0cHM6Ly9vYXV0aC52ay5jb20vYXl\" />\n";

Pattern pattern = Pattern.compile("(\"ip_h\"|\"lg_h\"|\"to\").*value\\=\"(.*?)\"");
Matcher matcher = pattern.matcher(form);
List<String> foundValues = new ArrayList<>();
while (matcher.find()) {
    foundValues.add(matcher.group(2));
}

// Display List in Console...
for (int i = 0; i < foundValues.size(); i++) {
    System.out.println(foundValues.get(i));
}

// If you want to have all the found items placed
// into a one Dimensional String Array then you can
// use this code:
String[] itemsFound = foundValues.toArray(new String[0]);

// Display Array in Console...
System.out.println();
for (int i = 0; i < itemsFound.length; i++) {
    System.out.println(itemsFound[i]);
}