切换字符大小写,php

tar*_*eld 10 php string case

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

$str = "Hello, My Name is Tom";
Run Code Online (Sandbox Code Playgroud)

运行代码后,我得到一个这样的结果:

$newstr = "hELLO, mY nAME Is tOM";
Run Code Online (Sandbox Code Playgroud)

这甚至可能吗?

Mik*_*ike 62

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

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

print strtolower($str) ^ strtoupper($str) ^ $str;
Run Code Online (Sandbox Code Playgroud)

输出:

hELLO, mY nAME IS tOM
Run Code Online (Sandbox Code Playgroud)

  • 那个好漂亮! (6认同)
  • 我不明白为什么这不是公认的答案. (3认同)

小智 9

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

$str = "Hello, My Name is Tom";
echo strtr($str, 
           'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
           'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ');
Run Code Online (Sandbox Code Playgroud)


mwi*_*rek 6

最快的方法是使用位掩码。没有笨重的字符串函数或正则表达式。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;
}
Run Code Online (Sandbox Code Playgroud)

这就是它的改变:

$string{$i} = chr($char ^ 32);
Run Code Online (Sandbox Code Playgroud)

我们取第 N 个字符$string并执行 XOR (^),告诉解释器取 的整数值$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
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

我们可以逆转它:

0110 0001 // 97 (A)
0010 0000 // Bitmask of 32
---------
0100 0001 // 65 (a)
Run Code Online (Sandbox Code Playgroud)

不需要str_replaceor preg_replace,我们只需交换位以从字符的 ASCII 值中添加或减去 32,然后交换大小写。第 6 位(右起第 6 位)确定字符是大写还是小写。如果是 0,则为小写;如果为大写,则为 1。将位从 0 更改为 1 等于 32,得到大写chr()值,从 1 更改为 0 则减去 32,将大写字母变为小写。

swapCase('userId'); // USERiD
swapCase('USERiD'); // userId
swapCase('rot13'); // ROT13
Run Code Online (Sandbox Code Playgroud)

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

// $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
Run Code Online (Sandbox Code Playgroud)


Lei*_*igh 5

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

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

@xtempore 的解释:

'a' ^ ' '返回A。它之所以有效,A是因为0x41 和a0x61(对于所有 AZ 也是如此),并且因为空格是 0x20。通过异或运算,您正在翻转那一点。简单来说,您是在大写字母上加上 32 使它们变成小写,然后从小写字母中减去 32 使它们变成大写。


Ign*_*ams 3

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

  • 这可能仅适用于 ASCII 字符。`strotolower()` 的替代方案可能是 `mb_strtolower()`。 (2认同)