2010-03-01 14 views
27

zakładamy dwa obiekty Java String:Czy Java toLowerCase() zachowuje oryginalną długość łańcucha?

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

Czy to prawda, że ​​wówczas dla każdej wartości <my string> wyrażenie

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

ocenia się true?

Czy zatem String.toLowerCase() zachowuje oryginalną długość łańcucha dla dowolnej wartości ciągu?

Odpowiedz

41

Zaskakuje, że nie jest to ani !!

z Java docs toLowerCase

Zamienia wszystkie znaki w tym ciągu na małe litery przy użyciu reguł danego Locale. Mapowania Case polegają w znacznym stopniu na danych znakowych specyfikacji Unicode. Ponieważ odwzorowania przypadków nie zawsze zawierają odwzorowania znaków 1: 1, wynikowy ciąg może być innej długości niż oryginalny ciąg.

Przykład:

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) 
    } 
} 
+5

Czy możesz wymienić kilka przykładów? Znam kilka przykładów, które spowodowałyby, że wariant z dużymi literami różniłby się od wielkości małych liter, np. 'ß' stanie się' SS', ale nie na odwrót. – BalusC

+10

+1: javadocs - tak blisko, a jednak daleko ... – MicSim

+7

@BalusC: Istnieje kilka fantazyjnych reguł dotyczących łączenia znaków w locjach AZ, LT i TR, patrz 'java/lang/ConditionalSpecialCasing.java'. Na przykład '\ u00cc" .toLowerCase (nowe ustawienie regionalne ("lt")). Length() == 3' – axtavt

4

Przede wszystkim chciałbym podkreślić, że ja absolutnie zgadzam się z (obecnie najwyżej oceniane) Odpowiedź z @codaddict.

Ale chciałem zrobić eksperyment, więc tutaj jest:

To nie jest formalny dowód, ale kod ten pobiegł za mną, nigdy nie osiągając wnętrze if (używając JDK 1.6.0 Aktualizacja 16 na Ubuntu):

Edit: Oto niektóre zaktualizowany kod, który obsługuje Locales także:

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

Uruchomienie tego kodu z nazwiskami locale m w zaakceptowanej odpowiedzi podam kilka przykładów. Uruchomienie go bez argumentów spowoduje wypróbowanie wszystkich dostępnych ustawień narodowych (i zajmie sporo czasu!).

Nie jest obszerna, ponieważ teoretycznie mogą istnieć łańcuchy znaków, które zachowują się inaczej, ale to dobre pierwsze przybliżenie.

Należy również pamiętać, że wiele kombinacji dwuznakowych wytworzonych w ten sposób prawdopodobnie nieprawidłowy UTF-16, więc fakt, że eksploduje nic w tym kodzie można obwiniać tylko na bardzo solidnej API String w Javie.

I na koniec: nawet jeśli założenie jest prawdziwe dla aktualnej implementacji Javy, może łatwo zmienić się, gdy przyszłe wersje Javy będą implementować przyszłe wersje standardu Unicode, w których zasady nowych znaków mogą wprowadzać sytuacje gdzie to już nie jest prawdą.

Tak więc w zależności od tego wciąż jest to zły pomysł.

+3

Należy pamiętać, że kod, który zapisałeś, jest zależny od ustawień narodowych. Nie oczywiste, ale paskudne. –

2

Należy również pamiętać, że toUpperCase() również nie zachowuje długości. Przykład: "straße" staje się "STRASSE" dla niemieckiego locale. Więc jesteś mniej lub bardziej wkręcony, jeśli pracujesz z łańcuchami rozróżniającymi małe i małe litery i musisz przechowywać indeks dla czegoś.

+0

Ponieważ zarówno straße, jak i strasse są poprawną pisownią (ignorując fakt, że powinny mieć początkowy kapitał S, ponieważ są rzeczownikami), zakładam, że spowoduje to ciekawy efekt uboczny, że przechodzenie do wielkich liter i odwrotnych spowoduje inny ciąg znaków ? Próbowałeś tego? – Fredrik

Powiązane problemy