即使在阅读了所有评论之后,您的要求还是有点模糊。鉴于您的示例和解释,我假设您的要求如下:
- 输入是由 (x)html 标签组成的字符串。您的示例不包含此内容,但我假设输入可以在标签之间包含文本。
- 在您的问题中,我们不关心嵌套。因此,输入实际上只是与标签混合的文本,其中开始、结束和自结束标签都被认为是等效的。
- 标签可以包含带引号的值。
- 您想要截断字符串,以便字符串不会在标签中间被截断。因此,在截断的字符串中,每个“”字符。
我将为您提供两种解决方案,一种简单的解决方案可能不正确,具体取决于输入的具体情况,另一种更复杂的解决方案是正确的。
第一个解决方案
对于第一个解决方案,我们首先找到截断大小之前的最后一个“>”字符(这对应于完全关闭的最后一个标签)。该字符之后可能会出现不属于任何标签的文本,因此我们随后搜索最后一个闭合标签之后的第一个“
public static String truncate1(String input, int size)
{
if (input.length() < size) return input;
int pos = input.lastIndexOf('>', size);
int pos2 = input.indexOf('<', pos);
if (pos2 < 0 || pos2 >= size) {
return input.substring(0, size);
}
else {
return input.substring(0, pos2);
}
}
当然,此解决方案不考虑带引号的值字符串:“”字符可能出现在字符串内,在这种情况下应忽略它们。无论如何,我提到了解决方案,因为您提到您的输入已被清理,因此您可能可以确保带引号的字符串永远不会包含“”字符。
第二种解决方案
为了考虑带引号的字符串,我们不能再依赖标准 Java 类,但我们必须自己扫描输入并记住当前是否在标签内和字符串内。如果我们在字符串之外遇到“
public static String truncate2(String input, int size)
{
if (input.length() < size) return input;
int lastTagStart = 0;
boolean inString = false;
boolean inTag = false;
for (int pos = 0; pos < size; pos++) {
switch (input.charAt(pos)) {
case '<':
if (!inString && !inTag) {
lastTagStart = pos;
inTag = true;
}
break;
case '>':
if (!inString) inTag = false;
break;
case '\"':
if (inTag) inString = !inString;
break;
}
}
if (!inTag) lastTagStart = size;
return input.substring(0, lastTagStart);
}