[英]Invert case of all letters in a string (uppercase to lowercase and lowercase to uppercase)
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?这甚至可能吗?
If your string is ASCII only, you can use XOR:如果您的字符串仅为 ASCII,则可以使用 XOR:
$str = "Hello, My Name is Tom";
print strtolower($str) ^ strtoupper($str) ^ $str;
Outputs:输出:
hELLO, mY nAME IS tOM
OK I know you've already got an answer, but the somewhat obscure strtr() function is crying out to be used for this ;)好的,我知道您已经有了答案,但是有点晦涩的 strtr() 函数迫切需要用于此目的;)
$str = "Hello, My Name is Tom";
echo strtr($str,
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ');
Very similar in function to the answer by Mark.在功能上与马克的答案非常相似。
preg_replace_callback(
'/[a-z]/i',
function($matches) {
return $matches[0] ^ ' ';
},
$str
)
Explanation by @xtempore: @xtempore 的解释:
'a' ^ ' '
returnsA
.'a' ^ ' '
返回A
。 It works becauseA
is 0x41 anda
is 0x61 (and likewise for all AZ), and because a space is 0x20.之所以有效
A
是因为A
是 0x41,a
是 0x61(对于所有 AZ 也是如此),并且因为空格是 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.
简单来说,您是在大写字母上加上 32 使它们变成小写,并从小写字母中减去 32 使它们变成大写。
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..:
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;
}
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.我们取
$string
的第 N 个字符并执行 XOR (^) 告诉解释器取$char
的整数值并将第 6 位 (32) 从 1 交换为 0 或 0 到 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()
:所有 ASCII 字符都与对应字符相差 32(因此 ASCII 是一个巧妙的设计。由于 32 是 2 的幂 (2^5),因此很容易移位。要获取字母的 ASCII 值,请使用内置的在 PHP 函数
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.因此,您使用
strlen()
作为for
循环的中间部分来遍历字符串,并且它将准确地循环您的字符串包含字母的次数。 If the character at position $i
is a letter (az (65-90) or AZ (97-122)), it will swap that character for the uppercase or lowercase counterpart using a bitmask.如果
$i
位置的字符是字母(az (65-90) 或 AZ (97-122)),它将使用位掩码将该字符替换为大写或小写对应字符。
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.不需要
str_replace
或preg_replace
,我们只需交换位以从字符的 ASCII 值中添加或减去 32 并交换大小写。 The 6th bit (6th from the right) determines if the character is uppercase or lowercase.第 6 位(右起第 6 位)确定字符是大写还是小写。 If it's a 0, it's lowercase and 1 if uppercase.
如果是 0,则为小写,如果为大写,则为 1。 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.将位从 0 更改为 1 广告 32,获得大写
chr()
值,从 1 更改为 0 减去 32,将大写字母变为小写。
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
您需要遍历字符串测试每个字符的大小写,根据需要调用strtolower()
或strtoupper()
,将修改后的字符添加到新字符串。
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 ):多功能版本:(在这里找到 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);
}
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);
}
Following script supports UTF-8 characters like "ą" etc.以下脚本支持 UTF-8 字符,如“ą”等。
PHP 7.1+ 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+ 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ŚĆżź $before
: aaAAąAŚĆżź
$after
: AAaaĄaśćŻŹ $after
: AAaaĄaśćŻŹ
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
ie you :即你:
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...现在的一个想法是使用
mb_strtolower
和mb_strtoupper
:它可能有助于特殊字符和多字节编码......
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?这有可能吗?
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.对于多字节/Unicode 安全解决方案,我可能会建议根据哪个捕获组包含一个字母来改变/切换每个字母的大小写。 This way you don't have to make a multibyte-base check after matching a letter with regex.
这样您就不必在将字母与正则表达式匹配后进行多字节基础检查。
$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.请参阅有关如何匹配可能是多字节的字母的答案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.