Сохраняет ли Java toLowerCase() исходную длину строки?

StackOverflow https://stackoverflow.com/questions/2357315

  •  23-09-2019
  •  | 
  •  

Вопрос

Предположим, что есть два объекта Java String:

String str = "<my string>";
String strLower = str.toLowerCase();

Верно ли тогда, что для любого значения <my string> выражение

str.length() == strLower.length()

оценивается как true?

Итак, делает String.toLowerCase() сохранить исходную длину строки для любого значения String?

Это было полезно?

Решение

Удивительно, но это так нет!!

Из документации Java в нижний регистр

Преобразует все символы в этой строке в нижний регистр, используя правила данного языкового стандарта.Сопоставление регистра основано на версии стандарта Юникода, указанной классом символов. Поскольку сопоставления регистра не всегда являются сопоставлениями символов 1:1, результирующая строка может иметь длину, отличную от исходной строки.

Пример:

package com.stackoverflow.q2357315;

import java.util.Locale;

public class Test {
    public static void main(String[] args) throws Exception {
        Locale.setDefault(new Locale("lt"));
        String s = "\u00cc";
        System.out.println(s + " (" + s.length() + ")"); // Ì (1)
        s = s.toLowerCase();
        System.out.println(s + " (" + s.length() + ")"); // i̇̀ (3)
    }
}

Другие советы

Прежде всего, я хотел бы отметить, что я абсолютно согласен с ответом @codaddict (на данный момент имеющим самый высокий рейтинг).

Но мне захотелось провести эксперимент, и вот он:

Это не формальное доказательство, но у меня этот код выполнялся, даже не достигнув внутренней части if (с использованием JDK 1.6.0, обновление 16 в Ubuntu):

Редактировать: Вот обновленный код, который также обрабатывает локали:

import java.util.Locale;

public class ToLowerTester {
    public final Locale locale;

    public ToLowerTester(final Locale locale) {
        this.locale = locale;
    }

    public String findFirstStrangeTwoLetterCombination() {
        char[] b = new char[2];
        for (char c1 = 0; c1 < Character.MAX_VALUE; c1++) {
            b[0] = c1;
            for (char c2 = 0; c2 < Character.MAX_VALUE; c2++) {
                b[1] = c2;
                final String string = new String(b);
                String lower = string.toLowerCase(locale);
                if (string.length() != lower.length()) {
                    return string;
                }
            }
        }
        return null;
    }
    public static void main(final String[] args) {
        Locale[] locales;
        if (args.length != 0) {
            locales = new Locale[args.length];
            for (int i=0; i<args.length; i++) {
                locales[i] = new Locale(args[i]);
            }
        } else {
            locales = Locale.getAvailableLocales();
        }
        for (Locale locale : locales) {
            System.out.println("Testing " + locale + "...");
            String result = new ToLowerTester(locale).findFirstStrangeTwoLetterCombination();
            if (result != null) {
                String lower = result.toLowerCase(locale);
                System.out.println("Found strange two letter combination for locale "
                    + locale + ": <" + result + "> (" + result.length() + ") -> <"
                    + lower + "> (" + lower.length() + ")");
            }
        }
    }
}

Запуск этого кода с именами локалей, упомянутыми в принятом ответе, приведет к печати нескольких примеров.Запуск без аргументов проверит все доступные локали (и это займет довольно много времени!).

Это не так уж и обширно, потому что теоретически могут существовать многосимвольные строки, которые ведут себя по-разному, но это хорошее первое приближение.

Также обратите внимание, что многие из двухсимвольных комбинаций, созданных таким образом, вероятно, являются недопустимыми UTF-16, поэтому в том, что в этом коде ничего не происходит, можно винить только очень надежный String API в Java.

И последнее но не менее важное:даже если предположение верно для текущей реализации Java, оно может легко измениться, как только будущие версии Java реализуют будущие версии стандарта Unicode, в которых правила для новых символов могут создавать ситуации, когда это больше не соответствует действительности.

Так что зависеть от этого все еще довольно плохая идея.

Также помните, что toUpperCase() также не сохраняет длину.Пример:«straße» становится «STRASSE» для немецкого языка.Итак, вы более или менее облажались, если работаете со строками, чувствительными к регистру, и вам нужно для чего-то сохранить индекс.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top