反转字符串中所有字母的大小写(大写转小写和小写转大写)

发布于 2024-08-20 23:49:31 字数 184 浏览 4 评论 0原文

如何交换/切换字符串中字符的大小写,例如:

$str = "Hello, My Name is Tom";

运行代码后,我得到如下结果:

$newstr = "hELLO, mY nAME Is tOM";

这可能吗?

How can I swap around / toggle the case of the characters in a string, for example:

$str = "Hello, My Name is Tom";

After I run the code I get a result like this:

$newstr = "hELLO, mY nAME Is tOM";

Is this even possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

第七度阳光i 2024-08-27 23:49:31

如果您的字符串仅为 ASCII,则可以使用 XOR:

$str = "Hello, My Name is Tom";

print strtolower($str) ^ strtoupper($str) ^ $str;

输出:

hELLO, mY nAME IS tOM

If your string is ASCII only, you can use XOR:

$str = "Hello, My Name is Tom";

print strtolower($str) ^ strtoupper($str) ^ $str;

Outputs:

hELLO, mY nAME IS tOM
我要还你自由 2024-08-27 23:49:31

好吧,我知道你已经得到了答案,但是有点晦涩的 strtr() 函数迫切需要用于此目的;)

$str = "Hello, My Name is Tom";
echo strtr($str, 
           'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
           'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ');

OK I know you've already got an answer, but the somewhat obscure strtr() function is crying out to be used for this ;)

$str = "Hello, My Name is Tom";
echo strtr($str, 
           'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
           'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ');
在你怀里撒娇 2024-08-27 23:49:31

最快的方法是使用位掩码。没有笨重的字符串函数或正则表达式。 PHP 是 C 的包装器,因此如果您知道 OR、NOT、AND、XOR、NAND 等逻辑函数,我们可以很容易地操作位。:

function swapCase($string) {
    for ($i = 0; $i < strlen($string); $i++) {
        $char = ord($string{$i});
        if (($char > 64 && $char < 91) || ($char > 96 && $char < 123)) {
            $string{$i} = chr($char ^ 32);
        }
    }
    return $string;
}

这就是改变它的原因:

$string{$i} = chr($char ^ 32);

我们取 中的第 N 个字符$string 并执行异或 (^),告诉解释器获取 $char 的整数值,并将第 6 位 (32) 从 1 交换为 0 或 0 交换为 1

。 ASCII 字符与其对应字符相差 32(正因为如此,ASCII 是一个巧妙的设计。由于 32 是 2 的幂 (2^5),因此很容易移位。要获取字母的 ASCII 值,请使用内置的PHP 函数 ord()

ord('a') // 65
ord('A') // 97
// 97 - 65 = 32

因此,您使用 strlen() 作为 for 循环的中间部分来循环字符串,它将循环恰好是字符串包含字母的次数。如果位置 $i 的字符是字母(az (65-90) 或 AZ (97-122)),它将将该字符交换为字母。使用位掩码的大写或小写对应部分

如下是位掩码的工作原理:

0100 0001 // 65 (lowercase a)
0010 0000 // 32 (bitmask of 32)
--------- // XOR means: we put a 1 if the bits are different, a 0 if they are same.
0110 0001 // 97 (uppercase A)

我们可以反转它:

0110 0001 // 97 (A)
0010 0000 // Bitmask of 32
---------
0100 0001 // 65 (a)

不需要 str_replacepreg_replace,我们只需交换位即可加或减 32根据字符的 ASCII 值,我们交换大小写。第 6 位(右起第 6 位)确定字符是大写还是小写。如果是 0,则为小写;如果为大写,则为 1。将位从 0 更改为 1 和 32,获取大写的 chr() 值,然后从 1 更改为 0 减去 32,将大写字母变为小写。

swapCase('userId'); // USERiD
swapCase('USERiD'); // userId
swapCase('rot13'); // ROT13

我们还可以有一个函数来交换特定字符的大小写:

// $i = position in string
function swapCaseAtChar($string, $i) {
    $char = ord($string{$i});
    if (($char > 64 && $char < 91) || ($char > 96 && $char < 123)) {
        $string{$i} = chr($char ^ 32);
        return $string;
    } else {
        return $string;
    }
}

echo swapCaseAtChar('iiiiiiii', 0); // Iiiiiiii
echo swapCaseAtChar('userid', 4); // userId

// Numbers are no issue
echo swapCaseAtChar('12345qqq', 7); // 12345qqQ

The quickest way is with a bitmask. No clunky string functions or regex. PHP is a wrapper for C, so we can manipulate bits quite easily if you know your logical function like OR, NOT, AND, XOR, NAND, etc..:

function swapCase($string) {
    for ($i = 0; $i < strlen($string); $i++) {
        $char = ord($string{$i});
        if (($char > 64 && $char < 91) || ($char > 96 && $char < 123)) {
            $string{$i} = chr($char ^ 32);
        }
    }
    return $string;
}

This is what changes it:

$string{$i} = chr($char ^ 32);

We take the Nth character in $string and perform an XOR (^) telling the interpreter to take the integer value of $char and swapping the 6th bit (32) from a 1 to 0 or 0 to 1.

All ASCII characters are 32 away from their counterparts (ASCII was an ingenious design because of this. Since 32 is a power of 2 (2^5), it's easy to shift bits. To get the ASCII value of a letter, use the built in PHP function ord():

ord('a') // 65
ord('A') // 97
// 97 - 65 = 32

So you loop through the string using strlen() as the middle part of the for loop, and it will loop exactly the number of times as your string has letters. If the character at position $i is a letter (a-z (65-90) or A-Z (97-122)), it will swap that character for the uppercase or lowercase counterpart using a bitmask.

Here's how the bitmask works:

0100 0001 // 65 (lowercase a)
0010 0000 // 32 (bitmask of 32)
--------- // XOR means: we put a 1 if the bits are different, a 0 if they are same.
0110 0001 // 97 (uppercase A)

We can reverse it:

0110 0001 // 97 (A)
0010 0000 // Bitmask of 32
---------
0100 0001 // 65 (a)

No need for str_replace or preg_replace, we just swap bits to add or subtract 32 from the ASCII value of the character and we swap cases. The 6th bit (6th from the right) determines if the character is uppercase or lowercase. If it's a 0, it's lowercase and 1 if uppercase. Changing the bit from a 0 to a 1 ads 32, getting the uppercase chr() value, and changing from a 1 to a 0 subtracts 32, turning an uppercase letter lowercase.

swapCase('userId'); // USERiD
swapCase('USERiD'); // userId
swapCase('rot13'); // ROT13

We can also have a function that swaps the case on a particular character:

// $i = position in string
function swapCaseAtChar($string, $i) {
    $char = ord($string{$i});
    if (($char > 64 && $char < 91) || ($char > 96 && $char < 123)) {
        $string{$i} = chr($char ^ 32);
        return $string;
    } else {
        return $string;
    }
}

echo swapCaseAtChar('iiiiiiii', 0); // Iiiiiiii
echo swapCaseAtChar('userid', 4); // userId

// Numbers are no issue
echo swapCaseAtChar('12345qqq', 7); // 12345qqQ
苏辞 2024-08-27 23:49:31

功能与马克的答案非常相似。

preg_replace_callback(
    '/[a-z]/i',
    function($matches) {
        return $matches[0] ^ ' ';
    },
    $str
)

@xtempore 的解释:

'a' ^ ' ' 返回 A。它之所以有效,是因为 A 是 0x41,a 是 0x61(对于所有 AZ 也是如此),而且空格是 0x20。通过异或运算,您将翻转该位。简单来说,您将大写字母加 32 使其变为小写,并从小写字母中减去 32 使其变为大写。

Very similar in function to the answer by Mark.

preg_replace_callback(
    '/[a-z]/i',
    function($matches) {
        return $matches[0] ^ ' ';
    },
    $str
)

Explanation by @xtempore:

'a' ^ ' ' returns A. It works because A is 0x41 and a is 0x61 (and likewise for all A-Z), and because a space is 0x20. By xor-ing you are flipping that one bit. In simple terms, you are adding 32 to upper case letters making them lower case and subtracting 32 from lower case letters making them upper case.

情定在深秋 2024-08-27 23:49:31

您需要遍历字符串测试每个字符的大小写,根据需要调用 strtolower()strtoupper(),将修改后的字符添加到新字符串中。

You'll need to iterate through the string testing the case of each character, calling strtolower() or strtoupper() as appropriate, adding the modified character to a new string.

套路撩心 2024-08-27 23:49:31

我知道这个问题已经很老了 - 但这是我的两种多字节实现风格。

多功能版本:
mb_str_split 函数在此处找到):

function mb_str_split( $string ) { 
   # Split at all position not after the start: ^ 
   # and not before the end: $ 
   return preg_split('/(?<!^)(?!$)/u', $string ); 
}

function mb_is_upper($char) {
   return mb_strtolower($char, "UTF-8") != $char;
}

function mb_flip_case($string) {
   $characters = mb_str_split($string);
   foreach($characters as $key => $character) {
       if(mb_is_upper($character))
           $character = mb_strtolower($character, 'UTF-8');
       else
           $character = mb_strtoupper($character, 'UTF-8');

       $characters[$key] = $character;
   }
   return implode('',$characters);
}

单函数版本:

function mb_flip_case($string) {
    $characters = preg_split('/(?<!^)(?!$)/u', $string );
    foreach($characters as $key => $character) {
        if(mb_strtolower($character, "UTF-8") != $character)
            $character = mb_strtolower($character, 'UTF-8');
        else
            $character = mb_strtoupper($character, 'UTF-8');

        $characters[$key] = $character;
    }
    return implode('',$characters);
}

I know this question is old - but here's my 2 flavours of a multi-byte implementation.

Multi function version:
(mb_str_split function found here):

function mb_str_split( $string ) { 
   # Split at all position not after the start: ^ 
   # and not before the end: $ 
   return preg_split('/(?<!^)(?!$)/u', $string ); 
}

function mb_is_upper($char) {
   return mb_strtolower($char, "UTF-8") != $char;
}

function mb_flip_case($string) {
   $characters = mb_str_split($string);
   foreach($characters as $key => $character) {
       if(mb_is_upper($character))
           $character = mb_strtolower($character, 'UTF-8');
       else
           $character = mb_strtoupper($character, 'UTF-8');

       $characters[$key] = $character;
   }
   return implode('',$characters);
}

Single function version:

function mb_flip_case($string) {
    $characters = preg_split('/(?<!^)(?!$)/u', $string );
    foreach($characters as $key => $character) {
        if(mb_strtolower($character, "UTF-8") != $character)
            $character = mb_strtolower($character, 'UTF-8');
        else
            $character = mb_strtoupper($character, 'UTF-8');

        $characters[$key] = $character;
    }
    return implode('',$characters);
}
清欢 2024-08-27 23:49:31

以下脚本支持 UTF-8 字符,如“ą”等。

  • PHP 7.1+

    $before = 'aaAAAąAŚĆżź';
    $after = preg_replace_callback('/./u', function (array $char) {
        [$char] = $char;
    
        返回 $char === ($charLower = mb_strtolower($char))
        ? mb_strtoupper($char)
        :$charLower;
    }, $之前);
    
  • PHP 7.4+

    $before = 'aaAAAąAŚĆżź';
    $after = implode(array_map(function (string $char) {
        返回 $char === ($charLower = mb_strtolower($char))
        ? mb_strtoupper($char)
        :$charLower;
    }, mb_str_split($before)));
    

$before: aaAAąAŚĆżź

$after: AAaaĄaśćŻŹ

Following script supports UTF-8 characters like "ą" etc.

  • PHP 7.1+

    $before = 'aaAAąAŚĆżź';
    $after = preg_replace_callback('/./u', function (array $char) {
        [$char] = $char;
    
        return $char === ($charLower = mb_strtolower($char))
        ? mb_strtoupper($char)
        : $charLower;
    }, $before);
    
  • PHP 7.4+

    $before = 'aaAAąAŚĆżź';
    $after = implode(array_map(function (string $char) {
        return $char === ($charLower = mb_strtolower($char))
        ? mb_strtoupper($char)
        : $charLower;
    }, mb_str_split($before)));
    

$before: aaAAąAŚĆżź

$after: AAaaĄaśćŻŹ

雅心素梦 2024-08-27 23:49:31

我想一个解决方案可能是使用这样的东西:

$str = "Hello, My Name is Tom";
$newStr = '';
$length = strlen($str);
for ($i=0 ; $i<$length ; $i++) {
    if ($str[$i] >= 'A' && $str[$i] <= 'Z') {
        $newStr .= strtolower($str[$i]);
    } else if ($str[$i] >= 'a' && $str[$i] <= 'z') {
        $newStr .= strtoupper($str[$i]);
    } else {
        $newStr .= $str[$i];
    }
}
echo $newStr;

这让你:

hELLO, mY nAME IS tOM

即你:

  • 循环遍历原始字符串的每个字符
  • ,如果它在A和Z之间,如果它在a和z之间,你把它变成小写,
  • 你把它变成大写,
  • 否则,你保持原样

问题是这将可能不能很好地处理像重音这样的特殊字符:-(

这里有一个快速建议,可能(或可能不)适用于其他一些角色:

$str = "Hello, My Name is Tom";
$newStr = '';
$length = strlen($str);
for ($i=0 ; $i<$length ; $i++) {
    if (strtoupper($str[$i]) == $str[$i]) {
        // Putting to upper case doesn't change the character
        // => it's already in upper case => must be put to lower case
        $newStr .= strtolower($str[$i]);
    } else {
        // Putting to upper changes the character
        // => it's in lower case => must be transformed to upper case
        $newStr .= strtoupper($str[$i]);
    }
}
echo $newStr;

现在的一个想法是使用mb_strtolowermb_strtoupper :它可能有助于处理特殊字符和多字节编码...

I suppose a solution might be to use something like this :

$str = "Hello, My Name is Tom";
$newStr = '';
$length = strlen($str);
for ($i=0 ; $i<$length ; $i++) {
    if ($str[$i] >= 'A' && $str[$i] <= 'Z') {
        $newStr .= strtolower($str[$i]);
    } else if ($str[$i] >= 'a' && $str[$i] <= 'z') {
        $newStr .= strtoupper($str[$i]);
    } else {
        $newStr .= $str[$i];
    }
}
echo $newStr;

Which gets you :

hELLO, mY nAME IS tOM

i.e. you :

  • loop over each character of the original string
  • if it's between A and Z, you put it to lower case
  • if it's between a and z, you put it to upper case
  • else, you keep it as-is

The problem being this will probably not work nicely with special character like accents :-(

And here is a quick proposal that might (or might not) work for some other characters :

$str = "Hello, My Name is Tom";
$newStr = '';
$length = strlen($str);
for ($i=0 ; $i<$length ; $i++) {
    if (strtoupper($str[$i]) == $str[$i]) {
        // Putting to upper case doesn't change the character
        // => it's already in upper case => must be put to lower case
        $newStr .= strtolower($str[$i]);
    } else {
        // Putting to upper changes the character
        // => it's in lower case => must be transformed to upper case
        $newStr .= strtoupper($str[$i]);
    }
}
echo $newStr;

An idea, now, would be to use mb_strtolower and mb_strtoupper : it might help with special characters, and multi-byte encodings...

孤檠 2024-08-27 23:49:31

对于多字节/unicode 安全的解决方案,我可能建议根据哪个捕获组包含一个字母来改变/切换每个字母的大小写。这样,您就不必在将字母与正则表达式匹配后进行多字节基础检查。

代码:(演示

$string = 'aaAAąAŚĆżź';
echo preg_replace_callback(
         '/(\p{Lu})|(\p{Ll})/u',
         function($m) {
             return $m[1]
                 ? mb_strtolower($m[1])
                 : mb_strtoupper($m[2]);
         },
         $string
     );
// AAaaĄaśćŻŹ

请参阅这个答案关于如何匹配可能是多字节的字母。

For a multibyte/unicode-safe solution, I'd probably recommend mutating/toggling the case of each letter based on which capture group contains a letter. This way you don't have to make a multibyte-base check after matching a letter with regex.

Code: (Demo)

$string = 'aaAAąAŚĆżź';
echo preg_replace_callback(
         '/(\p{Lu})|(\p{Ll})/u',
         function($m) {
             return $m[1]
                 ? mb_strtolower($m[1])
                 : mb_strtoupper($m[2]);
         },
         $string
     );
// AAaaĄaśćŻŹ

See this answer about how to match letters that might be multibyte.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文