Stanadrd Java String.substring methods may not properly handle Unicode charactesr that exceed two chars, potentially causing issues like symbols. To address this problem, I developed a solution inspired by Apache Commons StringUtils.
The implementation considers multi-language character boundaries:
/**
* Natural language substring method similar to {@link StringUtils#substring(String, int, int)}
* Handles multi-language character extraction problems for use with nvarchar type field truncation
* @param inputText string to extract
* @param beginPos starting position (inclusive)
* @param finishPos ending position (exclusive)
* @return processed substring
*/
public static String extractNaturalText(String inputText, int beginPos, int finishPos) {
if (inputText == null) {
return null;
}
// process negative values
int totalCodePoints = inputText.codePointCount(0, inputText.length());
if (finishPos < 0) {
finishPos = totalCodePoints + finishPos;
}
if (beginPos < 0) {
beginPos = totalCodePoints + beginPos;
}
// validate range
if (finishPos > totalCodePoints) {
finishPos = totalCodePoints;
}
// return empty if invalid range
if (beginPos > finishPos) {
return "";
}
if (beginPos < 0) {
beginPos = 0;
}
if (finishPos < 0) {
finishPos = 0;
}
StringBuilder outputBuilder = new StringBuilder();
int counter = 0;
int index = 0;
if (beginPos > 0) {
// skip initial characters
for (; index < inputText.length() && counter < beginPos; index++, counter++) {
if (Character.isHighSurrogate(inputText.charAt(index))) {
index++;
}
}
}
if (finishPos < totalCodePoints) {
for (; index < inputText.length() && counter < finishPos; index++, counter++) {
outputBuilder.append(inputText.charAt(index));
if (Character.isHighSurrogate(inputText.charAt(index))) {
outputBuilder.append(inputText.charAt(++index));
}
}
} else {
return inputText.substring(index, inputText.length());
}
return outputBuilder.toString();
}
Test cases:
// "\uD83D\uDF01" represents 🜁
// "\uD801\uDC00" represents 𐐀
String sampleData = "🜁𐐀🜁𐐀𐐀🜁🜁𐐀𐐀𐐀";
System.out.println(TextProcessor.extractNaturalText(sampleData, 0, 1));
System.out.println(TextProcessor.extractNaturalText(sampleData, 0, 3));
System.out.println(TextProcessor.extractNaturalText(sampleData, 1, 3));
System.out.println(TextProcessor.extractNaturalText(sampleData, 4, 8));
System.out.println(TextProcessor.extractNaturalText(sampleData, 4, 100));
System.out.println(sampleData.substring(1, 3));
The results demonstrate proper handling of multi-byte Unicode characters, ensuring expected behavior when working with international text.