Сохраняет ли Java toLowerCase () исходную длину строки? - PullRequest
28 голосов
/ 01 марта 2010

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

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

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

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

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

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

Ответы [ 3 ]

44 голосов
/ 01 марта 2010

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

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

Преобразует все символы в этой строке в нижний регистр, используя правила данной локали. Отображение регистра основано на версии Unicode Standard, указанной классом Character. Поскольку сопоставления регистра не всегда являются сопоставлениями символов 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)
    }
}
4 голосов
/ 01 марта 2010

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

Но я хотел провести эксперимент, поэтому вот оно:

Это не формальное доказательство, но этот код работал для меня, даже не доходя до внутренней части if (используя JDK 1.6.0 Update 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, в которых правила для новых символов могут вводить ситуации, когда это больше не верно.

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

2 голосов
/ 09 февраля 2011

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

...