У C # яка різниця між ToUpper () та ToUpperInvariant ()?


133

У C #, в чому різниця між ToUpper()і ToUpperInvariant()?

Чи можете ви навести приклад, коли результати можуть бути різними?


3
[Організація] Чи повинен цей питання мати тег "інтернаціоналізація"?
jasso

Відповіді:


154

ToUpperвикористовує сучасну культуру. ToUpperInvariantвикористовує інваріантну культуру.

Канонічний приклад - Туреччина, де верхній регістр "я" не є "Я".

Приклад коду, що показує різницю:

using System;
using System.Drawing;
using System.Globalization;
using System.Threading;
using System.Windows.Forms;

public class Test
{
    [STAThread]
    static void Main()
    {
        string invariant = "iii".ToUpperInvariant();
        CultureInfo turkey = new CultureInfo("tr-TR");
        Thread.CurrentThread.CurrentCulture = turkey;
        string cultured = "iii".ToUpper();

        Font bigFont = new Font("Arial", 40);
        Form f = new Form {
            Controls = {
                new Label { Text = invariant, Location = new Point(20, 20),
                            Font = bigFont, AutoSize = true},
                new Label { Text = cultured, Location = new Point(20, 100),
                            Font = bigFont, AutoSize = true }
            }
        };        
        Application.Run(f);
    }
}

Докладніше про турецьку мову дивіться у цій публікації в блозі "Тест Туреччини" .

Я би не здивувався, почувши, що навколо сповзаючих символів існують різні проблеми з великою буквою тощо. Це лише один приклад, який я знаю з вершини голови ... почасти тому, що він мене покусав років тому на Яві, де я був вище -встановлення рядка та порівняння його з "MAIL". У Туреччині це було не так добре ...


45
ха-ха, я читав, що думає ... "" Туреччина "не має літери" я "в ній"
Джефф Меркадо,

Наближається 2019 рік, і у мене Visual Studio пропонує ımageв якості назви поля для Imageі Unity 3D спамувати внутрішню помилку консолі Unable to find key name that matches 'rıght'на "англійській" Windows з регіональними налаштуваннями для дати та часу. Схоже, іноді навіть Microsoft не вдається провести тест на Туреччину, мова ПК навіть не турецька, просто хаха.
Guney Ozsan

28

Відповідь Джона ідеальна. Я просто хотів додати, що ToUpperInvariantце те саме, що дзвонити ToUpper(CultureInfo.InvariantCulture).

Це робить приклад Джона трохи простішим:

using System;
using System.Drawing;
using System.Globalization;
using System.Threading;
using System.Windows.Forms;

public class Test
{
    [STAThread]
    static void Main()
    {
        string invariant = "iii".ToUpper(CultureInfo.InvariantCulture);
        string cultured = "iii".ToUpper(new CultureInfo("tr-TR"));

        Application.Run(new Form {
            Font = new Font("Times New Roman", 40),
            Controls = { 
                new Label { Text = invariant, Location = new Point(20, 20), AutoSize = true }, 
                new Label { Text = cultured, Location = new Point(20, 100), AutoSize = true }, 
            }
        });
    }
}

Я також використовував New Times Roman, оскільки це крутіший шрифт.

Я також встановив властивість Form' Fontзамість двох Labelелементів керування, оскільки Fontвластивість передається у спадок.

І я скоротив кілька інших рядків тільки тому, що мені подобається компактний (наприклад, не виробничий) код.

Мені справді було нічого кращого робити на даний момент.


5
"Відповідь Джона ідеальна". Поговоріть про зайве твердження. ;)
krillgar

1
Метод ToUpper не має для мене перевантаження параметрів? старіша версія була? Я не розумію
batmaci

Я не знаю, це задокументовано тут: msdn.microsoft.com/en-us/library/system.string.toupper.aspx
Tergiver


12

String.ToUpperі String.ToLowerможе давати різні результати за різних культур. Найвідоміший приклад - турецький приклад , для якого перетворення малої латиниці "i" у великі регістри призводить не до великої літери "Я", а до турецької "Я".

Великі літери I залежно від культури, верхній ряд - малі літери, нижній ряд - великі літери

Що стосується мене, це було плутати навіть із наведеним вище зображенням ( джерелом ), я написав програму (див. Вихідний код нижче), щоб побачити точний вихід для турецького прикладу:

# Lowercase letters
Character              | UpperInvariant | UpperTurkish | LowerInvariant | LowerTurkish
English i - i (\u0069) | I (\u0049)     | I (\u0130)   | i (\u0069)     | i (\u0069)
Turkish i - ı (\u0131) | ı (\u0131)     | I (\u0049)   | ı (\u0131)     | ı (\u0131)

# Uppercase letters
Character              | UpperInvariant | UpperTurkish | LowerInvariant | LowerTurkish
English i - I (\u0049) | I (\u0049)     | I (\u0049)   | i (\u0069)     | ı (\u0131)
Turkish i - I (\u0130) | I (\u0130)     | I (\u0130)   | I (\u0130)     | i (\u0069)

Як ви можете бачити:

  1. Великі великі літери та малі великі літери дають різні результати для інваріантної культури та турецької культури.
  2. Великі великі літери та малі літери не мають жодного ефекту, незалежно від культури.
  3. Culture.CultureInvariant залишає турецьких символів такими, які є
  4. ToUpperі ToLowerє оборотними, тобто знижуючи символи після верхньогозакриття, приводять його в початковий вигляд до тих пір, поки для обох операцій використовувалася одна і та ж культура.

За даними MSDN , для Char.ToUpper і Char.ToLower турецькі та азербайджанські є єдиними постраждалими культурами, оскільки вони єдині з однозначними відмінностями в корпусі. Для рядків може впливати більше культур.


Вихідний код консольної програми, що використовується для отримання виводу:

using System;
using System.Globalization;
using System.Linq;
using System.Text;

namespace TurkishI
{
    class Program
    {
        static void Main(string[] args)
        {
            var englishI = new UnicodeCharacter('\u0069', "English i");
            var turkishI = new UnicodeCharacter('\u0131', "Turkish i");

            Console.WriteLine("# Lowercase letters");
            Console.WriteLine("Character              | UpperInvariant | UpperTurkish | LowerInvariant | LowerTurkish");
            WriteUpperToConsole(englishI);
            WriteLowerToConsole(turkishI);

            Console.WriteLine("\n# Uppercase letters");
            var uppercaseEnglishI = new UnicodeCharacter('\u0049', "English i");
            var uppercaseTurkishI = new UnicodeCharacter('\u0130', "Turkish i");
            Console.WriteLine("Character              | UpperInvariant | UpperTurkish | LowerInvariant | LowerTurkish");
            WriteLowerToConsole(uppercaseEnglishI);
            WriteLowerToConsole(uppercaseTurkishI);

            Console.ReadKey();
        }

        static void WriteUpperToConsole(UnicodeCharacter character)
        {
            Console.WriteLine("{0,-9} - {1,10} | {2,-14} | {3,-12} | {4,-14} | {5,-12}",
                character.Description,
                character,
                character.UpperInvariant,
                character.UpperTurkish,
                character.LowerInvariant,
                character.LowerTurkish
            );
        }

        static void WriteLowerToConsole(UnicodeCharacter character)
        {
            Console.WriteLine("{0,-9} - {1,10} | {2,-14} | {3,-12} | {4,-14} | {5,-12}",
                character.Description,
                character,
                character.UpperInvariant,
                character.UpperTurkish,
                character.LowerInvariant,
                character.LowerTurkish
            );
        }
    }


    class UnicodeCharacter
    {
        public static readonly CultureInfo TurkishCulture = new CultureInfo("tr-TR");

        public char Character { get; }

        public string Description { get; }

        public UnicodeCharacter(char character) : this(character, string.Empty) {  }

        public UnicodeCharacter(char character, string description)
        {
            if (description == null) {
                throw new ArgumentNullException(nameof(description));
            }

            Character = character;
            Description = description;
        }

        public string EscapeSequence => ToUnicodeEscapeSequence(Character);

        public UnicodeCharacter LowerInvariant => new UnicodeCharacter(Char.ToLowerInvariant(Character));

        public UnicodeCharacter UpperInvariant => new UnicodeCharacter(Char.ToUpperInvariant(Character));

        public UnicodeCharacter LowerTurkish => new UnicodeCharacter(Char.ToLower(Character, TurkishCulture));

        public UnicodeCharacter UpperTurkish => new UnicodeCharacter(Char.ToUpper(Character, TurkishCulture));


        private static string ToUnicodeEscapeSequence(char character)
        {
            var bytes = Encoding.Unicode.GetBytes(new[] {character});
            var prefix = bytes.Length == 4 ? @"\U" : @"\u";
            var hex = BitConverter.ToString(bytes.Reverse().ToArray()).Replace("-", string.Empty);
            return $"{prefix}{hex}";
        }

        public override string ToString()
        {
            return $"{Character} ({EscapeSequence})";
        }
    }
}

Таблиця справ була дуже корисною. Дякую!
VoteCoffee


2

в англійській мові немає різниці. лише в турецькій культурі різницю можна знайти.


13
І ви впевнені, що турецька - єдина культура в світі, яка має інші правила щодо великих рекордів, ніж англійська? Мені важко повірити.
Джоель Мюллер

3
Турецька - найчастіше вживаний приклад, але не єдиний. І мова, а не культура має чотири різних Я. Все-таки +1 для турецької.
Армстронгест

впевнений, що повинні бути деякі інші. більшість ppl ніколи ніколи не зустрінеться з цими мовами в програмуванні
Stefanvds

8
Впевнені, що будуть. Веб-додатки відкриті для земної кулі, і добре встановити параметри. Що робити, якщо ви працюєте зі застарілою базою даних, яка не робить unicode? Які символи ви приймете як ім’я користувача? Що робити, якщо вам доведеться ввести імена клієнтів у Legacy ERP, побудований на COBOL? Дуже багато випадків, коли культура важлива. Не кажучи вже про дати та цифри. 4.54 написано 4,54 деякими мовами. Прикидаючись, що інші мови не існують, у довгостроковій перспективі ви не дуже далеко.
Армстронгест

Очевидно, що культури важливі для дат і чисел, я просто кажу, що більшість ppl ніколи не зустрінеться з мовами, які мають різний результат у toUpper та toUpperInvariant.
Стефанівд
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.