Чтобы сделать его простым и надежным, используйте CharsetEncoder
:
/** replaces any invalid character in Latin1 by the character rep */
public static String latin1(String str, char rep) {
CharsetEncoder cs = StandardCharsets.ISO_8859_1.newEncoder()
.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE)
.replaceWith(new byte[] { (byte) rep });
try {
ByteBuffer b = cs.encode(CharBuffer.wrap(str));
return new String(b.array(), StandardCharsets.ISO_8859_1);
} catch (CharacterCodingException e) {
throw new RuntimeException(e); // should not happen
}
}
. Это заменит каждый недопустимый набор символов в ISO_8859_1 (= Latin1) заменяющим символом rep
(что, конечно,, должен быть действительным символом Latin1).
Если вы согласны с заменой по умолчанию ('?'
), вы можете упростить ее:
public static String latin1(String str) {
return new String(str.getBytes(StandardCharsets.ISO_8859_1),
StandardCharsets.ISO_8859_1);
}
Например:
public static void main(String[] args) {
String x = "hi Œmar!";
System.out.println("'" + x + "' -> '" + latin1(x,'?') + "'");
}
output 'hi Œmar!' -> 'hi ?mar!'
Возможный недостаток этого подхода состоит в том, что вы можете заменять каждый недопустимый символ только одним заменяющим символом - вы не можете удалить его или использовать многосимвольную последовательность.Если вы хотите этого, и если вы достаточно уверены, что какой-то символ никогда не появится в вашей строке, вы можете пойти на обычные грязные приемы - например, предполагая, что \u0000
никогда не появится:
/* removes invalid Latin1 charaters - assumes the zero character never appears */
public static String latin1removeinvalid(String str) {
return latin1(str,(char)0).replace("\u0000", "");
}
Добавлено: если вы хотите проверить только действительность, тогда проще:
public static boolean isValidLatin1(String str) {
return StandardCharsets.ISO_8859_1.newEncoder().canEncode(str);
}