在C#字符串中反转所有字母字符的大小写

11
什么是将C#字符串中所有字母的大小写反转的最简单方法?例如, "aBc1$;" 应变为 "AbC1$;" 我可以轻松地编写一个方法来实现这一点,但我希望有一个库调用可以使这更容易。我也想避免拥有所有已知字母字符并将每个字符与列表中的内容进行比较。也许可以用正则表达式来实现,但我不太了解它们。谢谢。
谢谢帮助。我创建了一个字符串扩展方法,大部分灵感来自Anthony Pegram的解决方案,但没有使用LINQ。我认为这在可读性和性能之间取得了很好的平衡。这是我想出的方法。
public static string SwapCase(this string source) {
    char[] caseSwappedChars = new char[source.Length];
    for(int i = 0; i < caseSwappedChars.Length; i++) {
        char c = source[i];
        if(char.IsLetter(c)) {
            caseSwappedChars[i] =
                char.IsUpper(c) ? char.ToLower(c) : char.ToUpper(c);
        } else {
            caseSwappedChars[i] = c;
        }
    }
    return new string(caseSwappedChars);
}

1
注意:我的答案中有一些国际化注释。 - ErikE
10个回答

23

你可以使用LINQ一行完成它。一个方法:

string input = "aBc1$";
string reversedCase = new string(
    input.Select(c => char.IsLetter(c) ? (char.IsUpper(c) ?
                      char.ToLower(c) : char.ToUpper(c)) : c).ToArray());

8
如果您不关心国际化:
string input = "aBc1$@[\\]^_{|{~";
Encoding enc = new System.Text.ASCIIEncoding();
byte[] b = enc.GetBytes(input);
for (int i = input.Length - 1; i >= 0; i -= 1) {
   if ((b[i] & 0xdf) >= 65 && (b[i] & 0xdf) <= 90) { //check if alpha
      b[i] ^= 0x20; // then XOR the correct bit to change case
   }
}
Console.WriteLine(input);
Console.WriteLine(enc.GetString(b));

如果你关心国际化,那么在使用 ToUpper() 和 ToLower() 函数时,你需要传入 CultureInfo.InvariantCulture。...

3
这是一个很好的技巧,使用异或运算,很多人可能不知道。任何字母与32(0x20)进行异或运算将产生相反的大小写形式。 - Kibbee
1
@Kibbee 感谢您的解释。我可能应该在我的帖子中提到它。无论如何,这个技巧只适用于普通ASCII字符... - ErikE

3
如果您不了解LINQ,您可以老派一些来完成它。
static string InvertCasing(string s)
{
    char[] c = s.ToCharArray();
    char[] cUpper = s.ToUpper().ToCharArray();
    char[] cLower = s.ToLower().ToCharArray();

    for (int i = 0; i < c.Length; i++)
    {
        if (c[i] == cUpper[i])
        {
            c[i] = cLower[i];
        }
        else
        {
            c[i] = cUpper[i];
        }
    }

    return new string(c);
}

3

这里有一个使用正则表达式的方法:

string input = "aBcdefGhI123jKLMo$";
string result = Regex.Replace(input, "[a-zA-Z]",
                            m => Char.IsUpper(m.Value[0]) ?
                                 Char.ToLower(m.Value[0]).ToString() :
                                 Char.ToUpper(m.Value[0]).ToString());
Console.WriteLine("Original: " + input);
Console.WriteLine("Modified: " + result);

您可以使用Char.Parse(m.Value)来代替m.Value[0]。此外,要注意使用ToUpperInvariantToLowerInvariant方法。更多信息请参见此问题:在C#中ToUpper()和ToUpperInvariant()有什么区别?

2
我为字符串制作了一个扩展方法,它可以做到这一点!
public static class InvertStringExtension
{
    public static string Invert(this string s)
    {
        char[] chars = s.ToCharArray();
        for (int i = 0; i < chars.Length; i++)
            chars[i] = chars[i].Invert();

        return new string(chars);
    }
}

public static class InvertCharExtension
{
    public static char Invert(this char c)
    {
        if (!char.IsLetter(c))
            return c;

        return char.IsUpper(c) ? char.ToLower(c) : char.ToUpper(c);
    }
}

使用
var hello = "hELLO wORLD";
var helloInverted = hello.Invert();

// helloInverted == "Hello World"

1
        char[] carr = str.ToCharArray();
        for (int i = 0; i < carr.Length; i++)
        {
            if (char.IsLetter(carr[i]))
            {
                carr[i] = char.IsUpper(carr[i]) ? char.ToLower(carr[i]) : char.ToUpper(carr[i]);
            }
        }
        str = new string(carr);

1

昨天有人问了我一个类似的问题,我的回答是:

public static partial class StringExtensions {
    public static String InvertCase(this String t) {
        Func<char, String> selector=
            c => (char.IsUpper(c)?char.ToLower(c):char.ToUpper(c)).ToString();

        return t.Select(selector).Aggregate(String.Concat);
    }
}

您可以轻松更改方法签名,添加一个类型为CultureInfo的参数,并将其与像char.ToUpper这样的方法一起使用,以满足全球化的要求。


1
这种方法比这里列出的其他一些方法稍微快一点,而且它很好,因为它使用字符算术!
    var line = "someStringToSwapCase";

    var charArr = new char[line.Length];

    for (int i = 0; i < line.Length; i++)
    {
        if (line[i] >= 65 && line[i] <= 90)
        {
            charArr[i] = (char)(line[i] + 32);
        }
        else if (line[i] >= 97 && line[i] <= 122)
        {
            charArr[i] = (char)(line[i] - 32);
        }
        else
        {
            charArr[i] = line[i];
        }
    }

    var res = new String(charArr);

1
以下代码每个字母仅进行 2 次函数调用。我们可以直接应用大小写转换,而无需检查是否为字母。
    string result="";
    foreach (var item in S)
        {
        if (char.ToLower(item) != item )
            result+= char.ToLower(item);
        else
            result+= char.ToUpper(item);
        }

也可以创建一个额外的变量,并在检查之前将其设置为char.ToLower(item),这样可以减少一个函数调用,但可读性会稍差一些,如下所示:

    string result="";
    foreach (var item in S)
        {
        var temp=char.ToLower(item);
        if (temp != item )
            result+= temp;
        else
            result+= char.ToUpper(item);
        }

1

这会更有帮助,因为我没有直接使用函数。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Practice
{
    class Program
    {
        static void Main(string[] args)
        {
            char[] new_str = new char[50];
            string str;
            int ch;
            Console.Write("Enter String : ");
            str = Console.ReadLine();

            for (int i = 0; i < str.Length; i++)
            {
                ch = (int)str[i];
                if (ch > 64 && ch < 91)
                {
                    ch = ch + 32;
                    new_str[i] = Convert.ToChar(ch);
                }
                else
                {
                    ch = ch - 32;
                    new_str[i] = Convert.ToChar(ch);
                }
            }
            Console.Write(new_str);

            Console.ReadKey();
        }
    }
}

我相信这对你也会有用。谢谢。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接