Быстрый подсчет случаев - PullRequest
1 голос
/ 20 марта 2009

У меня есть большое количество строк для обработки в php. Я хочу «исправить» их, чтобы они были заглавными (используя ucwords(strtolower($str))), но только в том случае, если они уже прописные или строчные. Если это уже смешанный случай, я бы просто оставил их как есть.

Какой самый быстрый способ проверить это? Кажется, что for проникновение через строку было бы довольно медленным путем.

Вот что у меня есть, что, я думаю, будет слишком медленным:

function fixCase($str)
{
    $uc = 0;
    $lc = 0;
    for($i=0;$i<strlen($str);$i++)
    {
        if ($str[$i] >= 'a' && $str[$i] <= 'z')
            $lc++;
        else if ($str[$i] >= 'A' && $str[$i] <= 'Z')
            $uc++;
    }

    if ($uc == 0 || $lc == 0)
    {
        return ucwords(strtolower($str));
    }
}

Ответы [ 7 ]

6 голосов
/ 20 марта 2009

просто используйте сравнение строк (с учетом регистра)

function fixCase($str)
{
  if ( 
       (strcmp($str, strtolower($str)) === 0) || 
       (strcmp($str, strtoupper($str)) === 0) ) 
  {
    $str = ucwords(strtolower($str));
  }

  return $str;
}
1 голос
/ 21 марта 2009

Если причина, по которой вы хотите избежать исправления уже смешанных строк, заключается в эффективности, то, скорее всего, вы тратите время впустую, конвертируйте каждую строку независимо от ее текущего состояния:

function fixCase($str)
{
    return ucwords(strtolower($str));
}

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

Если, тем не менее, есть веская причина избегать преобразования уже смешанных строк, например, если вы хотите сохранить в оболочке некоторое предполагаемое значение, то да, ответ jcinacio, безусловно, самый простой и очень эффективный.

1 голос
/ 21 марта 2009

Вы можете попробовать функцию проверки регистра строки, которую я разместил здесь

function getStringCase($subject)
{
    if (!empty($subject))
    {
        if (preg_match('/^[^A-Za-z]+$/', $subject))
            return 0;   // no alphabetic characters
        else if (preg_match('/^[^A-Z]+$/', $subject))
            return 1;   // lowercase
        else if (preg_match('/^[^a-z]+$/', $subject))
            return 2;   // uppercase
        else
            return 3;   // mixed-case
    }
    else
    {
        return 0;   // empty
    }
}
1 голос
/ 20 марта 2009

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

Лично я бы просто перебрал символы строки с помощью такого алгоритма:

  • Посмотрите на первый символ в строке, установите переменную, указывающую, был ли он в верхнем или нижнем регистре.
  • Теперь изучите каждого персонажа последовательно. Если вы дошли до конца строки, и все они были в том же регистре, что и первый символ, исправьте регистр строки, как вам нравится.
  • Если любой символ отличается от первого символа, прервите цикл и верните строку.

Редактировать: фактический код, я думаю, что это примерно так же хорошо, как вы собираетесь получить.

// returns 0 if non-alphabetic char, 1 if uppercase, 2 if lowercase
function getCharType($char)
{
    if ($char >= 'A' && $char <= 'Z')
    {
        return 1;
    }
    else if ($char >= 'a' && $char <= 'z')
    {
        return 2;
    }
    else
    {
        return 0;
    }
}

function fixCase($str)
{
    for ($i = 0; $i < strlen($str); $i++)
    {
        $charType = getCharType($str[$i]);
        if ($charType != 0)
        {
            $firstCharType = $charType;
            break;
        }
    }

    for ($i = $i + 1; $i < strlen($str); $i++)
    {
        $charType = getCharType($str[$i]);
        if ($charType != $firstCharType && $charType != 0)
        {
            return $str;
        }
    }

    if ($firstCharType == 1) // uppercase, need to convert to lower first
    {
        return ucwords(strtolower($str));
    }
    else if ($firstCharType == 2) // lowercase, can just ucwords() it
    {
        return ucwords($str);
    }
    else // there were no letters at all in the string, just return it
    {
        return $str;
    }
}
0 голосов
/ 21 марта 2009

Обратите внимание, что все, что смотрит только на [A-Z], будет неверным, как только появятся символы ударения или умлаут. Оптимизация по скорости не имеет смысла, если результат неверный (эй, если результат не должен быть правильным, он может написать вам ДЕЙСТВИТЕЛЬНО быструю реализацию ...)

0 голосов
/ 21 марта 2009

Ну, я решил сделать тест из 2 предложенных ответов и моего оригинального решения. Я бы не думал, что результаты получатся такими, но я предполагаю, что нативные методы намного быстрее всех.

Код:

function method1($str)
{
    if (strcmp($str, strtolower($str)) == 0)
    {
        return ucwords($str);
    }
    else if (strcmp($str, strtoupper($str)) == 0)
    {
        return ucwords(strtolower($str));
    }
    else
    {
        return $str;
    }
}

// returns 0 if non-alphabetic char, 1 if uppercase, 2 if lowercase
function getCharType($char)
{
    if ($char >= 'A' && $char <= 'Z')
    {
        return 1;
    }
    else if ($char >= 'a' && $char <= 'z')
    {
        return 2;
    }
    else
    {
        return 0;
    }
}

function method2($str)
{
    for ($i = 0; $i < strlen($str); $i++)
    {
        $charType = getCharType($str[$i]);
        if ($charType != 0)
        {
            $firstCharType = $charType;
            break;
        }
    }

    for ($i = $i + 1; $i < strlen($str); $i++)
    {
        $charType = getCharType($str[$i]);
        if ($charType != $firstCharType && $charType != 0)
        {
            return $str;
        }
    }

    if ($firstCharType == 1) // uppercase, need to convert to lower first
    {
        return ucwords(strtolower($str));
    }
    else if ($firstCharType == 2) // lowercase, can just ucwords() it
    {
        return ucwords($str);
    }
    else // there were no letters at all in the string, just return it
    {
        return $str;
    }
}

function method0($str)
{
        $uc = 0;
        $lc = 0;
        for($i=0;$i<strlen($str);$i++)
        {
                if ($str[$i] >= 'a' && $str[$i] <= 'z')
                        $lc++;
                else if ($str[$i] >= 'A' && $str[$i] <= 'Z')
                        $uc++;
        }

        if ($uc == 0 || $lc == 0)
        {
                return ucwords(strtolower($str));
        }
}


function test($func,$s)
{
    $start = gettimeofday(true);
    for($i = 0; $i < 1000000; $i++)
    {
        $s4 = $func($s);
    }
    $end = gettimeofday(true);
    echo "$func Time: " . ($end-$start) . " - Avg: ".sprintf("%.09f",(($end-$start)/1000000))."\n";
}


$s1 = "first String";
$s2 = "second string";
$s3 = "THIRD STRING";

test("method0",$s1);
test("method0",$s2);
test("method0",$s3);

test("method1",$s1);
test("method1",$s2);
test("method1",$s3);

test("method2",$s1);
test("method2",$s2);
test("method2",$s3);

Результаты:

method0 Time: 19.2899270058 - Avg: 0.000019290
method0 Time: 20.8679389954 - Avg: 0.000020868
method0 Time: 24.8917310238 - Avg: 0.00002489   
method1 Time: 3.07466816902 - Avg: 0.000003075
method1 Time: 2.52559089661 - Avg: 0.000002526
method1 Time: 4.06261897087 - Avg: 0.000004063
method2 Time: 19.2718701363 - Avg: 0.000019272
method2 Time: 35.2485661507 - Avg: 0.000035249
method2 Time: 29.3357679844 - Avg: 0.000029336
0 голосов
/ 20 марта 2009

Не было бы проще проверить, если строка = нижний регистр (строка) или строка = верхний регистр (строка), и если так, оставьте это. В противном случае выполните вашу операцию.

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