簡體   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