Il semble que la méthode qui utilise pleinement NIO soit recommandée pour l'implémentation de la troncature par le nombre d'octets de String. Cependant, l'implémentation de la rue introduite en japonais ne semble pas fonctionner comme prévu sur l'environnement Android.
Si vous recherchez sur Google, les pages suivantes arriveront en haut. http://qiita.com/ota-meshi/items/16972156c935b8b7feaa http://d.hatena.ne.jp/kameid/20090314/1237025305
Le flux général de ces implémentations est le suivant.
Lorsque j'ai testé ce processus, j'ai obtenu les résultats suivants.
Type de test | Environnement d'exécution | résultat |
---|---|---|
Test unitaire local | Android Studio OpenJDK | "AIUE" |
Test instrumenté | Émulateur Android | "AIUEO" |
L'implémentation ci-dessus est faite en supposant que la position CharBuffer est 4 lorsque l'encodage est coupé par Overflow. Cependant, sur l'émulateur Android ou la machine réelle, lorsque l'encodage a été coupé par Overflow, la position de CharBuffer a progressé jusqu'à 5, de sorte que la troncature ne fonctionnait pas comme prévu.
Juste au cas où, si vous vérifiez la description de la position de Charset Encoder, il semble que ce ne soit pas une explication aussi stricte. On peut s'attendre à ce que la position du côté écriture soit située à la fin au moment du débordement, mais le côté lecture est susceptible de changer en fonction de la mise en œuvre du jugement de débordement de chaque encodeur. J'ai pensé.
https://docs.oracle.com/javase/jp/8/docs/api/java/nio/charset/CharsetEncoder.html La position du buffer augmente avec le nombre de caractères lus ou le nombre d'octets écrits,
Lorsque j'ai contacté des pays anglophones pour effectuer une recherche sur Google, la page suivante a été introduite. https://theholyjava.wordpress.com/2007/11/02/truncating-utf-string-to-the-given/
La mise en œuvre ici est à peu près la suivante. C'est un processus qui ne dépend pas de la position du côté lecture lorsque le codage / décodage est terminé.
Avec cela comme référence, nous allons introduire une implémentation qui incorpore un jugement inutile de troncature précoce.
public static String truncate(String text, int capacity) {
if (text == null || capacity < 0) {
throw new IllegalArgumentException("invalid parameter.");
}
Charset charset = StandardCharsets.UTF_8;
CharsetEncoder encoder = charset.newEncoder()
.onMalformedInput(CodingErrorAction.IGNORE)
.onUnmappableCharacter(CodingErrorAction.IGNORE)
.reset();
// step 0.
int estimate = text.length() * (int) Math.ceil(encoder.maxBytesPerChar());
if (estimate <= capacity) {
return text;
}
// step 1.
ByteBuffer srcBuffer = ByteBuffer.allocate(capacity);
CoderResult result = encoder.encode(CharBuffer.wrap(text), srcBuffer, true);
encoder.flush(srcBuffer);
srcBuffer.flip();
if (result.isUnderflow()) {
return text;
}
// step 2.
CharBuffer dstBuffer = CharBuffer.allocate(text.length());
CharsetDecoder decoder = charset.newDecoder()
.onMalformedInput(CodingErrorAction.IGNORE)
.onUnmappableCharacter(CodingErrorAction.IGNORE)
.reset();
decoder.decode(srcBuffer, dstBuffer, true);
decoder.flush(dstBuffer);
dstBuffer.flip();
// step 3.
return dstBuffer.toString();
}
@Test
public void truncate() throws Exception {
//Caractère 1 octet
String testA = "abcde";
String testA_len0 = "";
String testA_len1 = "a";
String testA_len4 = "abcd";
String testA_len5 = "abcde";
assertThat(StringUtil.truncate(testA, 0), is(testA_len0));
assertThat(StringUtil.truncate(testA, 1), is(testA_len1));
assertThat(StringUtil.truncate(testA, 4), is(testA_len4));
assertThat(StringUtil.truncate(testA, 5), is(testA_len5));
//Caractère 3 octets
String testB = "AIUEO";
String testB_len0 = "";
String testB_len1 = "Ah";
String testB_len4 = "AIUE";
String testB_len5 = "AIUEO";
assertThat(StringUtil.truncate(testB, 0), is(testB_len0));
assertThat(StringUtil.truncate(testB, 2), is(testB_len0));
assertThat(StringUtil.truncate(testB, 3), is(testB_len1));
assertThat(StringUtil.truncate(testB, 14), is(testB_len4));
assertThat(StringUtil.truncate(testB, 15), is(testB_len5));
//Caractère 4 octets
//5 caractères
// https://www.softel.co.jp/blogs/tech/archives/596
String testC = "\uD840\uDC0B\uD844\uDE3D\uD844\uDF1B\uD845\uDC6E\uD846\uDCBD";
String testC_len0 = "";
String testC_len1 = "\uD840\uDC0B";
String testC_len4 = "\uD840\uDC0B\uD844\uDE3D\uD844\uDF1B\uD845\uDC6E";
String testC_len5 = "\uD840\uDC0B\uD844\uDE3D\uD844\uDF1B\uD845\uDC6E\uD846\uDCBD";
assertThat(StringUtil.truncate(testC, 3), is(testC_len0));
assertThat(StringUtil.truncate(testC, 4), is(testC_len1));
assertThat(StringUtil.truncate(testC, 19), is(testC_len4));
assertThat(StringUtil.truncate(testC, 20), is(testC_len5));
//Combinaison de caractères 1 octet et 3 octets
String testD = "A A B I C U D E E";
String testD_len1 = "A";
String testD_len2 = "A Ah";
String testD_len9 = "A A B I C U D E E";
String testD_len10 = "A A B I C U D E E";
assertThat(StringUtil.truncate(testD, 1), is(testD_len1));
assertThat(StringUtil.truncate(testD, 3), is(testD_len1));
assertThat(StringUtil.truncate(testD, 4), is(testD_len2));
assertThat(StringUtil.truncate(testD, 19), is(testD_len9));
assertThat(StringUtil.truncate(testD, 20), is(testD_len10));
//Pictogramme
//Drapeau japonais, BATH
// U+1F1EF U+1F1F5, U+1F6C0
// 4+4Byte + 4Byte
// http://qiita.com/_sobataro/items/47989ee4b573e0c2adfc
String testE = "\uD83C\uDDEF\uD83C\uDDF5\uD83D\uDEC0";
String testE_len0 = "";
String testE_len1 = "\uD83C\uDDEF";
String testE_len2 = "\uD83C\uDDEF\uD83C\uDDF5";
String testE_len3 = "\uD83C\uDDEF\uD83C\uDDF5\uD83D\uDEC0";
assertThat(StringUtil.truncate(testE, 3), is(testE_len0));
assertThat(StringUtil.truncate(testE, 4), is(testE_len1));
assertThat(StringUtil.truncate(testE, 7), is(testE_len1));
assertThat(StringUtil.truncate(testE, 8), is(testE_len2));
assertThat(StringUtil.truncate(testE, 11), is(testE_len2));
assertThat(StringUtil.truncate(testE, 12), is(testE_len3));
//Vérification de la longueur de la chaîne
assertEquals(1 + 1 + 1 + 1 + 1, testA.length());
assertEquals(1 + 1 + 1 + 1 + 1, testB.length());
assertEquals(2 + 2 + 2 + 2 + 2, testC.length());
assertEquals(2 + 2 + 2, testE.length());
}
Recommended Posts