如何交换/切换字符串中字符的大小写?例如:
$str = "Hello, My Name is Tom";
运行代码后,我得到了以下结果:
$newstr = "hELLO, mY nAME Is tOM";
这真的可能吗?
如果你的字符串只包含ASCII字符,你可以使用异或运算:
$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');
和 Mark 的回答在功能上非常相似。
preg_replace_callback(
'/[a-z]/i',
function($matches) {
return $matches[0] ^ ' ';
},
$str
)
@xtempore的解释:
'a' ^ ' '
返回A
。这个操作有效是因为A
是 0x41,a
是 0x61(其他所有的大写字母也是如此),空格是 0x20。通过异或操作,你可以翻转一个比特位。简单来说,你可以给大写字母加上32使它们变成小写字母,给小写字母减去32使它们变成大写字母。
'a' ^ ' '
似乎返回 0
。 - Sukimafunction 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 个字符,并对其执行异或(^)操作,告诉解释器获取整数值 $char
并交换第6位(32)从1到0或0到1的值。ord()
:ord('a') // 65
ord('A') // 97
// 97 - 65 = 32
所以你使用 strlen()
作为 for
循环的中间部分循环遍历字符串,它将正好遍历字符串中字母的数量次数。如果在位置 $i
的字符是一个字母 (a-z (65-90) 或 A-Z (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_replace
或preg_replace
,我们只需要交换位来从字符的ASCII值中加上或减去32,并交换大小写。第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()
,将修改后的字符添加到新字符串中。
strtolower()
的替代方法可能是mb_strtolower()
。 - Messa以下脚本支持像"ą"这样的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śćŻŹ
preg_replace_callback()
相比,preg_match_all()
就不太合适/直接了。 - mickmackusa我知道这个问题很老了 - 但这是我关于多字节实现的两种方式。
多功能版本: (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);
}
preg_split()
有一个可用的PREG_SPLIT_NO_EMPTY
标志。空胶水是implode()
的默认值,不需要声明。 - mickmackusa我想解决方案可能是使用类似这样的东西:
$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
即:
问题在于,这种方法可能无法很好地处理特殊字符,如重音符号 :-(
以下是一个快速提案,对于其他某些字符可能有效(也可能无效):
$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_strtolower
和 mb_strtoupper
:这可能有助于处理特殊字符和多字节编码...