我有一个构造了表达式的HTTP请求。到目前为止,表达式仍然有效,我可以将请求拆分为字符串数组,但是我想看看是否可以通过匹配单个捕获组来简化它。

所以:

private void process(final String message) {
     Pattern pattern = Pattern.compile("(GET|get){1}\\s(/.*)\\s(HTTP|http)(/1\\.0)");
     Matcher matcher = pattern.matcher(message);
}


请求是这样的:

GET / HTTP/1.0


很简单。因此,有什么方法可以遍历每个捕获组以检查是否存在匹配项?假设请求使用POST而不是GET,是否可以检查第一个捕获组,然后返回501“未实现”响应?

我的第一个解决方案是简单地按空格分割消息,然后检查每个单独的数组元素。但这似乎有点“不好”。

编辑:

问题是,matches()匹配整个对象,如果一组失败,那么整个表达式就会失败,这是我不希望的。任何数量的组都应该可以失败/成功,而不会引发IllegalStateException。

最佳答案

为了即使某些组不匹配也要匹配,它们必须是可选的。

然后使用Matcher#find()方法和Matcher#group(x)来访问组(从1开始,因为0是整个匹配项)。

例:

String msg = "GET HTTP 200 OK"; //resource and protocol version are left out by purpose

Pattern pattern = Pattern.compile("(GET|get)?\\s(/[^\\s]*)?\\s(HTTP|http)?(/1\\.0)?");
Matcher matcher = pattern.matcher( msg );

while ( matcher.find() )
{
  System.out.println(matcher.group( 1 ));  //prints GET
  System.out.println(matcher.group( 2 ));  //prints null since there's no resource
  System.out.println(matcher.group( 3 ));  //prints HTTP
  System.out.println(matcher.group( 4 ));  //prints null since there's no version string
}


附带说明一下,我需要稍微调整一下您的表情,因为第二组(/.*)会在第一个斜杠之后贪婪地匹配任何内容。但是,它仍然远非完美。



第二种方法可能是应用多个表达式/模式,并将它们一个接一个地应用于匹配器。

例:

Pattern methodPattern = Pattern.compile("GET|get");
Matcher matcher = methodPattern.matcher( msg );

if ( matcher.find() )
{
  System.out.println("method: " + matcher.group());
}

if ( matcher.usePattern( Pattern.compile("\\s/([^\\s]*)") ).find() )
{
  System.out.println("resource: " + matcher.group(1));
}

if ( matcher.usePattern( Pattern.compile("HTTP|http") ).find() )
{
  System.out.println("protocol: " + matcher.group());
}

if ( matcher.usePattern( Pattern.compile("/(\\d\\.\\d)") ).find() )
{
  System.out.println("version: " + matcher.group(1));
}


这利用了将匹配器的读取位置设置为匹配后的位置的事实,随后对find()的任何调用都将从该位置开始。如果模式不匹配,则位置保持不变。

因此,必须按顺序应用这些模式,但这些模式是可选的。

09-30 15:27
查看更多