[JAVA] Informationen zum Abschneiden von Zeichenfolgen um die Anzahl der Bytes unter Android

Es scheint, dass die Methode, die NIO vollständig nutzt, für die Implementierung der Kürzung um die Anzahl der Bytes von String empfohlen wird. Die Implementierung der auf Japanisch eingeführten Straße scheint jedoch in der Android-Umgebung nicht wie erwartet zu funktionieren.

Implementierung von Straßen durch NIO und Probleme

Wenn Sie bei Google suchen, werden die folgenden Seiten oben angezeigt. http://qiita.com/ota-meshi/items/16972156c935b8b7feaa http://d.hatena.ne.jp/kameid/20090314/1237025305

Der allgemeine Ablauf dieser Implementierungen ist wie folgt.

Als ich diesen Prozess getestet habe, habe ich die folgenden Ergebnisse erhalten.

Testtyp Ausführungsumgebung Ergebnis
Lokaler Einheitentest Android Studio OpenJDK "AIUE"
Instrumentierter Test Android Emulator "AIUEO"

Die obige Implementierung wird unter der Annahme durchgeführt, dass die CharBuffer-Position 4 ist, wenn die Codierung durch Überlauf unterbrochen wird. Auf dem Android-Emulator oder dem tatsächlichen Computer wurde die Position von CharBuffer jedoch auf 5 erhöht, als die Codierung durch Overflow unterbrochen wurde, sodass die Kürzung nicht wie erwartet funktionierte.

Nur für den Fall, wenn Sie die Beschreibung der Position des Charset-Encoders überprüfen, scheint es, dass dies keine so strenge Erklärung ist. Es scheint, dass erwartet werden kann, dass sich die Position auf der Schreibseite zum Zeitpunkt des Überlaufs am Ende befindet, aber die Leseseite wird sich wahrscheinlich abhängig von der Implementierung des Überlaufurteils jedes Codierers ändern. Ich dachte.

https://docs.oracle.com/javase/jp/8/docs/api/java/nio/charset/CharsetEncoder.html Die Position des Puffers erhöht sich mit der Anzahl der gelesenen Zeichen oder der Anzahl der geschriebenen Bytes.

Implementierung der Lösungsversion

Als ich mich an englischsprachige Länder wandte, um bei Google zu suchen, wurde die folgende Seite eingeführt. https://theholyjava.wordpress.com/2007/11/02/truncating-utf-string-to-the-given/

Die Implementierung hier ist ungefähr wie folgt. Es ist ein Prozess, der nicht von der Position auf der Leseseite abhängt, wenn das Codieren / Decodieren abgeschlossen ist.

Mit dieser Referenz werden wir eine Implementierung vorstellen, die eine frühzeitige, unnötige Beurteilung der Kürzung beinhaltet.


    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();
    }

Testcode

    @Test
    public void truncate() throws Exception {
        //1Byte Zeichen
        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));

        //3Byte Zeichen
        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));

        //4Byte Zeichen
        //5 Zeichen
        // 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));

        //Kombination von 1Byte- und 3Byte-Zeichen
        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));

        //Piktogramm
        //Japanische Flagge, 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));

        //Stringlängenprüfung
        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

Informationen zum Abschneiden von Zeichenfolgen um die Anzahl der Bytes unter Android
Über die Grundlagen der Android-Entwicklung
Über die Anzahl der Threads von Completable Future
Über den Umgang mit Null
[Ruby] Fragen und Überprüfung der Anzahl der Methodenargumente
Informationen zur Beschreibung von Docker-compose.yml
Ein Hinweis zum Seed-Feature von Ruby on Rails
Die Falle, die die Standardimplementierung der Java 8-Schnittstelle mit sich bringt
Über den Android-Lebenszyklus
Die Geschichte, das Verhalten von String durch Passieren von Java nicht zu kennen
Holen Sie sich die Beschleunigung und Ausrichtung des Weltkoordinatensystems auf Android
Über das Verhalten von Ruby Hash # ==
[Android] Holen Sie sich das Datum von Montag
Hinweis zum Pfad von request.getRequestDispatcher
Verschiedene Methoden der String-Klasse
Informationen zur Rolle der Initialisierungsmethode
Denken Sie an die 7 Regeln von Optional
Ich habe die Quelle von String gelesen
Sortieren Sie nach der Anzahl der Likes und der Seitennation
Informationen zur Protokollebene von java.util.logging.Logger
Lesen Sie den IC-Kontostand Ihres Studentenausweises (Felica) auf Android
[Android] Fügen Sie am Anfang mehrerer Zeilen eine beliebige Zeichenfolge hinzu
Was war keine faire Verwendung der Java-API-Umleitung unter Android?
Zeigen Sie Text über dem Bild an
Verstehen Sie die Grundlagen von Android Audio Record
Versuchen Sie, den Dienst auf Android Oreo zu verwenden
Asynchrone Verarbeitung durch RxJava (RxAndroid) unter Android
Was ist ein Test? ・ Über die Wichtigkeit eines Tests
Samshin über den Wert des versteckten Feldes
Informationen zur Funktionsweise von next () und nextLine ()
So bestimmen Sie die Anzahl der Parallelen
Informationen zur ersten Anzeige von Spring Framework
Rückblick auf die Grundlagen von Java
Über die Behandlung von BigDecimal (mit Reflexion)
[Java] Überprüfen Sie die Anzahl der Zeichen
Der Inhalt der von CarrierWave gespeicherten Daten.
Punkt 63: Beachten Sie die Leistung der Zeichenfolgenverkettung
Ansicht über anderen Apps auf Android anzeigen (Zusammenfassung der Unterstützungsmethoden nach API-Version)
String # split (String regex, int limit) Hinweis zu den Operationsspezifikationen des zweiten Arguments