我需要提取URL的子字符串。
URL
/service1/api/v1.0/foo
-> foo
/service1/api/v1.0/foo/{fooId}
-> foo/{fooId}
/service1/api/v1.0/foo/{fooId}/boo
-> foo/{fooId}/boo
其中一些URL可能具有请求参数。
代码
String str = request.getRequestURI();
str = str.substring(str.indexOf("/") + 1);
str = str.substring(str.indexOf("/") + 1);
str = str.substring(str.indexOf("/") + 1);
str = str.substring(str.indexOf("/") + 1, str.indexOf("?"));
是否有更好的方法来提取子字符串,而不是反复使用indexOf
方法?
答案 0 :(得分:1)
有很多替代方法:
在带有\
分隔符的分割字符串上使用Java-Stream API:
String str = "/service1/api/v1.0/foo/{fooId}/boo";
String[] split = str.split("\\/");
String url = Arrays.stream(split).skip(4).collect(Collectors.joining("/"));
System.out.println(url);
消除参数后,Stream将像:
String url = Arrays.stream(split)
.skip(4)
.map(i -> i.replaceAll("\\?.+", ""))
.collect(Collectors.joining("/"));
这也是Regex的位置!使用类Pattern和Matcher。
String str = "/service1/api/v1.0/foo/{fooId}/boo";
Pattern pattern = Pattern.compile("\\/.*?\\/api\\/v\\d+\\.\\d+\\/(.+)");
Matcher matcher = pattern.matcher(str);
while (matcher.find()) {
System.out.println(matcher.group(1));
}
如果您依赖indexOf(..)
的用法,则可能要使用while循环。
String str = "/service1/api/v1.0/foo/{fooId}/boo?parameter=value";
String string = str;
while(!string.startsWith("v1.0")) {
string = string.substring(string.indexOf("/") + 1);
}
System.out.println(string.substring(string.indexOf("/") + 1, string.indexOf("?")));
其他答案包括一种方法,如果前缀不可更改,则您可能只想使用一次idndexOf(..)
方法(@JB Nizet)的调用:
string.substring("/service1/api/v1.0/".length(), string.indexOf("?"));
所有这些解决方案都基于您的输入和事实,模式是已知的,或者至少是上一节的数字以\
或版本v1.0
为检查点-最佳解决方案由于网址的数量不受限制,因此此处可能不会出现。您必须知道输入URL的所有可能组合,才能找到最佳的处理方式。
答案 1 :(得分:0)
如何?
String s = "/service1/api/v1.0/foo/{fooId}/boo";
String[] sArray = s.split("/");
StringBuilder sb = new StringBuilder();
for (int i = 4; i < sArray.length; i++) {
sb.append(sArray[i]).append("/");
}
sb.deleteCharAt(sb.length() - 1);
System.out.println(sb.toString());
输出:
foo/{fooId}/boo
如果url前缀始终为/service1/api/v1.0/
,则只需执行s.substring("/service1/api/v1.0/".length())
。
答案 2 :(得分:0)
Path为此非常有用:
public static void main(String[] args) {
Path root = Paths.get("/service1/api/v1.0/foo");
Path relativize = root.relativize(Paths.get("/service1/api/v1.0/foo/{fooId}/boo"));
System.out.println(relativize);
}
输出:
{fooId} / boo
答案 3 :(得分:0)
这里有一些不错的选择。
1)如果您知道“ foo”将始终是第四个标记,那么您已经有了正确的想法。唯一的问题是您拥有提高效率所需的信息,但您并未使用它。不必多次复制String并从新String的开头重新开始,您只需从上次中断的地方继续4次,即可找到所需的起点。
String str = "/service1/api/v1.0/foo/{fooId}/boo";
// start at the beginning
int start = 0;
// get the 4th index of '/' in the string
for (int i = 0; i != 4; i++) {
// get the next index of '/' after the index 'start'
start = str.indexOf('/',start);
// increase the pointer to the next character after this slash
start++;
}
// get the substring
str = str.substring(start);
这将比任何正则表达式模式都高效得多。
2)正则表达式:(java.util.regex。*)。如果您想要的东西始终放在"service1/api/v1.0/"
之前,这将起作用。之前可能还有其他目录,例如"one/two/three/service1/api/v1.0/"
。
// \Q \E will automatically escape any special chars in the path
// (.+) will capture the matched text at that position
// $ marks the end of the string (technically it matches just before '\n')
Pattern pattern = Pattern.compile("/service1/api/v1\\.0/(.+)$");
// get a matcher for it
Matcher matcher = pattern.matcher(str);
// if there is a match
if (matcher.find()) {
// get the captured text
str = matcher.group(1);
}
如果您的路径可能有所不同,则可以使用正则表达式来解决。例如:也可以通过将正则表达式更改为"/service\\d*/api/v\\d+(?:\\.\\d+)?/(.+)(?:/|$)"