在C#中,ToUpper()和ToUpperInvariant()有什么区别?


133

在C#中,ToUpper()和之间有什么区别ToUpperInvariant()

您能否举一个例子,结果可能有所不同?


3
[组织]这个问题是否应该标记“国际化”?
jasso

Answers:


154

ToUpper使用当前的文化。ToUpperInvariant使用不变文化。

典型的例子是土耳其,其中“ i”的大写字母不是“ I”。

显示差异的示例代码:

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

有关土耳其语的更多信息,请参见土耳其测试博客文章

听到省略字符等还有其他大写问题,我不会感到惊讶。这只是我脑海中浮现的一个例子……部分原因是几年前它在Java中被我所困扰,当时我在上层-放置一个字符串并将其与“ MAIL”进行比较。在土耳其,效果不佳...


45
哈哈,我读到了这种想法……“'土耳其'里面没有字母'i'”
Jeff Mercado

快到2019年了,Visual Studio建议将其ımage作为字段名称,Image而Unity 3D则Unable to find key name that matches 'rıght'在带有土耳其语区域设置的日期和时间的“英语” Windows上向控制台发送内部错误消息。看起来有时甚至Microsoft都无法通过土耳其测试,PC的语言甚至不是土耳其语,只是哈哈。
Guney Ozsan '18 -10-28

28

乔恩的答案很完美。我只是想补充一点,ToUpperInvariant它与call相同ToUpper(CultureInfo.InvariantCulture)

这使Jon的示例更加简单:

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,因为它是一种更酷的字体。

我还设置了FormFont属性,而不是两个Label,因为控件Font属性是继承。

我减少了其他几行,只是因为我喜欢紧凑(示例,而不是生产)代码。

目前,我真的无可奈何。


5
“乔恩的答案是完美的。” 谈论多余的陈述。;)
krillgar

1
ToUpper方法对我来说没有任何参数重载吗?旧版本有吗?我不明白
batmaci



12

String.ToUpperString.ToLower在不同的文化下可以得出不同的结果。最著名的示例是土耳其语示例,对于该示例,将小写拉丁字母“ i”转换为大写字母不会产生大写拉丁字母“ I”,而会导致土耳其语“ I”。

I的大小写取决于文化,大写字母-小写字母,小写字母-大写字母

对于我来说,即使上面的图片(source)也令人困惑,我编写了一个程序(请参见下面的源代码)来查看土耳其语示例的确切输出:

# 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。
阿姆斯特朗

确定必须有其他人。无论如何,大多数人都永远不会在编程中遇到这些语言
Stefanvds 2010年

8
当然可以。Web应用程序向全球开放,最好设置参数。如果您在不执行unicode的旧数据库上运行怎么办?您将接受什么字符作为用户名?如果必须将客户名称放入基于COBOL构建的旧版ERP中怎么办?在很多情况下,文化很重要。更不用说日期和数字了。4.54是用某些语言编写的4,54。从长远来看,假装其他语言不存在不会让您走得太远。
阿姆斯特朗(Armstrongest)2010年

显然,文化对于日期和数字很重要,我只是告诉大多数人都不会满足在toUpper和toUpperInvariant中产生不同结果的语言。
Stefanvds
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.