Переключить регистр символов, php - PullRequest
10 голосов
/ 14 февраля 2010

Как мне поменять местами / переключить регистр символов в строке, например:

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

После запуска кода я получаю такой результат:

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

Возможно ли это вообще?

Ответы [ 8 ]

58 голосов
/ 07 июля 2011

Если ваша строка только ASCII, вы можете использовать XOR:

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

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

Выходы:

hELLO, mY nAME IS tOM
9 голосов
/ 14 февраля 2010

ОК, я знаю, что вы уже получили ответ, но несколько непонятная функция strtr () требует использования для этого;)

$str = "Hello, My Name is Tom";
echo strtr($str, 
           'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
           'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ');
4 голосов
/ 24 сентября 2012

Очень похоже на ответ Марком.

preg_replace_callback(
    '/[a-z]/i',
    function($matches) {
        return $matches[0] ^ ' ';
    },
    $str
)
2 голосов
/ 16 апреля 2017

Самый быстрый способ - с битовой маской. Нет неуклюжих строковых функций или регулярных выражений. 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);

Мы берем N-й символ в $string и выполняем XOR (^), сообщая интерпретатору принять целочисленное значение $char и меняя шестой бит (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 является буквой (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, мы просто меняем биты, чтобы сложить или вычесть 32 из значения ASCII символа, и мы поменяем регистры. 6-й бит (6-й справа) определяет, является ли символ прописным или строчным. Если это 0, это строчные буквы и 1, если прописные. Изменение бита с 0 на 1 для объявления 32, получение значения chr() в верхнем регистре и изменение вычитания 32 из 1 в 0, превращение буквы в верхний регистр в нижний регистр.

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
1 голос
/ 14 февраля 2010

Вам нужно будет перебирать строку, проверяя регистр каждого символа, вызывая strtolower() или strtoupper(), в зависимости от ситуации, добавляя измененный символ в новую строку.

0 голосов
/ 26 февраля 2016

Следующий скрипт поддерживает символы UTF-8, такие как «ą» и т. Д .:

<?php
$str = 'aaAAąAŚĆżź';
$newstr = '';
preg_match_all('#.#u', $str, $match);
foreach ($match[0] as $v)
 $newstr.= (($l=mb_strtolower($v, 'UTF-8')) === $v) ? mb_strtoupper($v, 'UTF-8') : $l;
echo $str, '<br/>', $newstr;
0 голосов
/ 03 сентября 2013

Я знаю, что этот вопрос старый, но вот мои 2 варианта многобайтовой реализации.

Многофункциональная версия: ( функция 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);
}
0 голосов
/ 14 февраля 2010

Я полагаю, что решением может быть использование чего-то вроде этого:

$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_strtolower и mb_strtoupper: это может помочь со специальными символами и многобайтовыми кодировками ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...