Java 字符串全部使用正则表达式替换为先行
Java String replace all using regex with lookahead
我正在尝试从传入的 HTTP 请求中获取规范化的 URI 以在日志中打印。这将帮助我们通过这个规范化的 URI 计算统计数据和其他数据。
为了规范化,我正在尝试使用 x
在 requestURI 上使用正则表达式对除版本(例如 v1)之外的所有数字和字母数字字符串进行字符串替换:
String str = "/v1/profile/abc13abc/13abc/cDe12/abc-bla/text_tw/HELLO/test/random/2234";
str.replaceAll("/([a-zA-Z]*[\d|\-|_]+[a-zA-Z]*)|([0-9]+)","/x");
这导致
/x/profile/x/x/x/x/x/HELLO/test/random/x
我想得到的结果是(不替换v1
)
/v1/profile/x/x/x/x/x/HELLO/test/random/x
我试过使用 skip look ahead
String.replaceAll("/(?!v1)([a-zA-Z]*[\d|\-|_]+[a-zA-Z]*)|([0-9]+)","/x");
但没有帮助。任何线索表示赞赏。
谢谢
使用
/(?:(?!v[1-4])[a-zA-Z]*[0-9_-]+[a-zA-Z]*|[0-9]+)
参见regex proof。
解释
--------------------------------------------------------------------------------
/ '/'
--------------------------------------------------------------------------------
(?: group, but do not capture:
--------------------------------------------------------------------------------
(?! look ahead to see if there is not:
--------------------------------------------------------------------------------
v 'v'
--------------------------------------------------------------------------------
[1-4] any character of: '1' to '4'
--------------------------------------------------------------------------------
) end of look-ahead
--------------------------------------------------------------------------------
[a-zA-Z]* any character of: 'a' to 'z', 'A' to 'Z'
(0 or more times (matching the most
amount possible))
--------------------------------------------------------------------------------
[0-9_-]+ any character of: '0' to '9', '_', '-'
(1 or more times (matching the most
amount possible))
--------------------------------------------------------------------------------
[a-zA-Z]* any character of: 'a' to 'z', 'A' to 'Z'
(0 or more times (matching the most
amount possible))
--------------------------------------------------------------------------------
| OR
--------------------------------------------------------------------------------
[0-9]+ any character of: '0' to '9' (1 or more
times (matching the most amount
possible))
--------------------------------------------------------------------------------
) end of grouping
添加了说明后,我将如何处理它。
- 创建一个元素列表,从第二个元素开始在
/
上拆分。
- 用第一个元素初始化字符串生成器。
- 然后简单地遍历从第二个元素开始的子列表。使用
String.matches
判断是否替换为x。
List<String> pathElements = Arrays.asList(str.substring(1).split("/"));
StringBuilder sb = new StringBuilder("/" + pathElements.get(0));
for(String pe : pathElements.subList(1,pathElements.size())) {
sb.append("/").append(pe.matches(".*[\d-_].*") ? "x" : pe);
}
System.out.println(sb);
打印
/v1/profile/x/x/x/x/x/HELLO/test/random/x
与其使用一个大的正则表达式,这对将来人们(可能包括你自己)来说将很难理解和维护,我会选择使用几行,这会使你的逻辑更加明显:
List<String> parts = Arrays.asList(path.split("/"));
parts.replaceAll(
p -> !p.matches("v\d+") && p.matches(".*[-_\d].*") ? "x" : p);
path = String.join("/", parts);
我正在尝试从传入的 HTTP 请求中获取规范化的 URI 以在日志中打印。这将帮助我们通过这个规范化的 URI 计算统计数据和其他数据。
为了规范化,我正在尝试使用 x
在 requestURI 上使用正则表达式对除版本(例如 v1)之外的所有数字和字母数字字符串进行字符串替换:
String str = "/v1/profile/abc13abc/13abc/cDe12/abc-bla/text_tw/HELLO/test/random/2234";
str.replaceAll("/([a-zA-Z]*[\d|\-|_]+[a-zA-Z]*)|([0-9]+)","/x");
这导致
/x/profile/x/x/x/x/x/HELLO/test/random/x
我想得到的结果是(不替换v1
)
/v1/profile/x/x/x/x/x/HELLO/test/random/x
我试过使用 skip look ahead
String.replaceAll("/(?!v1)([a-zA-Z]*[\d|\-|_]+[a-zA-Z]*)|([0-9]+)","/x");
但没有帮助。任何线索表示赞赏。
谢谢
使用
/(?:(?!v[1-4])[a-zA-Z]*[0-9_-]+[a-zA-Z]*|[0-9]+)
参见regex proof。
解释
--------------------------------------------------------------------------------
/ '/'
--------------------------------------------------------------------------------
(?: group, but do not capture:
--------------------------------------------------------------------------------
(?! look ahead to see if there is not:
--------------------------------------------------------------------------------
v 'v'
--------------------------------------------------------------------------------
[1-4] any character of: '1' to '4'
--------------------------------------------------------------------------------
) end of look-ahead
--------------------------------------------------------------------------------
[a-zA-Z]* any character of: 'a' to 'z', 'A' to 'Z'
(0 or more times (matching the most
amount possible))
--------------------------------------------------------------------------------
[0-9_-]+ any character of: '0' to '9', '_', '-'
(1 or more times (matching the most
amount possible))
--------------------------------------------------------------------------------
[a-zA-Z]* any character of: 'a' to 'z', 'A' to 'Z'
(0 or more times (matching the most
amount possible))
--------------------------------------------------------------------------------
| OR
--------------------------------------------------------------------------------
[0-9]+ any character of: '0' to '9' (1 or more
times (matching the most amount
possible))
--------------------------------------------------------------------------------
) end of grouping
添加了说明后,我将如何处理它。
- 创建一个元素列表,从第二个元素开始在
/
上拆分。 - 用第一个元素初始化字符串生成器。
- 然后简单地遍历从第二个元素开始的子列表。使用
String.matches
判断是否替换为x。
List<String> pathElements = Arrays.asList(str.substring(1).split("/"));
StringBuilder sb = new StringBuilder("/" + pathElements.get(0));
for(String pe : pathElements.subList(1,pathElements.size())) {
sb.append("/").append(pe.matches(".*[\d-_].*") ? "x" : pe);
}
System.out.println(sb);
打印
/v1/profile/x/x/x/x/x/HELLO/test/random/x
与其使用一个大的正则表达式,这对将来人们(可能包括你自己)来说将很难理解和维护,我会选择使用几行,这会使你的逻辑更加明显:
List<String> parts = Arrays.asList(path.split("/"));
parts.replaceAll(
p -> !p.matches("v\d+") && p.matches(".*[-_\d].*") ? "x" : p);
path = String.join("/", parts);