繁体   English   中英

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

[英]Invert case of all letters in a string (uppercase to lowercase and lowercase to uppercase)

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

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

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

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

这甚至可能吗?

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

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

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

输出:

hELLO, mY nAME IS tOM

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

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

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

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

@xtempore 的解释:

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

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

我们取$string的第 N 个字符并执行 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

因此,您使用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 ,我们只需交换位以从字符的 ASCII 值中添加或减去 32 并交换大小写。 第 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

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

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

多功能版本:(在这里找到 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);
}

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

  • 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śćŻŹ

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

$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 :它可能有助于特殊字符和多字节编码......

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

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

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

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

这有可能吗?

对于多字节/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śćŻŹ

请参阅有关如何匹配可能是多字节的字母的答案

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM