【发布时间】:2018-08-25 08:53:31
【问题描述】:
我有一行包含嵌套标记的文本(如{ 和}),我希望转换嵌套在特定深度的某些子字符串。
例如,在深度 1 处将单词 moo 大写:
moo [moo [moo moo]] moo ->
哞[哞[哞[哞]]哞
实现者:
replaceTokens(input, 1, "[", "]", "moo", String::toUpperCase);
或现实世界的示例,提供尚未使用颜色序列青色着色的“--options”:
@|blue --ignoreLog|@ 有效,但 --ignoreOutput 使一切静音。 ->
@|blue --ignoreLog|@ 有效,但@|cyan --ignoreOutput|@ 使一切静音。
实现者:
replaceTokens(input, 0, "@|", "|@", "--\\w*", s -> format("@|cyan %s|@", s));
我已经实现了这个逻辑,虽然我感觉很好(可能除了性能),但我也觉得我重新发明了轮子。以下是我的实现方式:
set currentPos to zero
while (input line not fully consumed) {
take the remaining line
if the open token is matched, add to output, increase counter and advance pos accordingly
else if the close token is matched, add to output, decrease counter and advance pos accordingly
else if the counter matches provided depth and given regex matches, invoke replacer function and advance pos accordingly
else just record the next character and advance pos by 1
}
这是实际的实现:
public static String replaceNestedTokens(String lineWithTokens, int nestingDepth, String tokenOpen, String tokenClose, String tokenRegexToReplace, Function<String, String> tokenReplacer) {
final Pattern startsWithOpen = compile(quote(tokenOpen));
final Pattern startsWithClose = compile(quote(tokenClose));
final Pattern startsWithTokenToReplace = compile(format("(?<token>%s)", tokenRegexToReplace));
final StringBuilder lineWithTokensReplaced = new StringBuilder();
int countOpenTokens = 0;
int pos = 0;
while (pos < lineWithTokens.length()) {
final String remainingLine = lineWithTokens.substring(pos);
if (startsWithOpen.matcher(remainingLine).lookingAt()) {
countOpenTokens++;
lineWithTokensReplaced.append(tokenOpen);
pos += tokenOpen.length();
} else if (startsWithClose.matcher(remainingLine).lookingAt()) {
countOpenTokens--;
lineWithTokensReplaced.append(tokenClose);
pos += tokenClose.length();
} else if (countOpenTokens == nestingDepth) {
Matcher startsWithTokenMatcher = startsWithTokenToReplace.matcher(remainingLine);
if (startsWithTokenMatcher.lookingAt()) {
String matchedToken = startsWithTokenMatcher.group("token");
lineWithTokensReplaced.append(tokenReplacer.apply(matchedToken));
pos += matchedToken.length();
} else {
lineWithTokensReplaced.append(lineWithTokens.charAt(pos++));
}
} else {
lineWithTokensReplaced.append(lineWithTokens.charAt(pos++));
}
assumeTrue(countOpenTokens >= 0, "Unbalanced token sets: closed token without open token\n\t" + lineWithTokens);
}
assumeTrue(countOpenTokens == 0, "Unbalanced token sets: open token without closed token\n\t" + lineWithTokens);
return lineWithTokensReplaced.toString();
}
我无法使用像this 或this(或扫描仪)解决方案这样的正则表达式,但我觉得我正在重新发明轮子,并且可以使用(vanilla Java)解决这个问题-box 类的代码更少。此外,我很确定这是所有内联模式/匹配器实例和子字符串的性能噩梦。
建议?
【问题讨论】:
标签: java regex java.util.scanner tokenize