Самый быстрый способ сделать нечувствительную к регистру подстроку ищет в C/C++?

Вы не инициализировали опцию Spinner из viewOfLayout.

9
задан msw 28 September 2015 в 03:09
поделиться

7 ответов

Код, который Вы отправили, является приблизительно половиной с такой скоростью, как strcasestr.

$ gcc -Wall -o my_stristr my_stristr.c
steve@solaris:~/code/tmp
$ gcc -Wall -o strcasestr strcasestr.c 
steve@solaris:~/code/tmp
$ ./bench ./my_stristr > my_stristr.result ; ./bench ./strcasestr > strcasestr.result;
steve@solaris:~/code/tmp
$ cat my_stristr.result 
run 1... time = 6.32
run 2... time = 6.31
run 3... time = 6.31
run 4... time = 6.31
run 5... time = 6.32
run 6... time = 6.31
run 7... time = 6.31
run 8... time = 6.31
run 9... time = 6.31
run 10... time = 6.31
average user time over 10 runs = 6.3120
steve@solaris:~/code/tmp
$ cat strcasestr.result 
run 1... time = 3.82
run 2... time = 3.82
run 3... time = 3.82
run 4... time = 3.82
run 5... time = 3.82
run 6... time = 3.82
run 7... time = 3.82
run 8... time = 3.82
run 9... time = 3.82
run 10... time = 3.82
average user time over 10 runs = 3.8200
steve@solaris:~/code/tmp

main функция была:

int main(void)
{
        char * needle="hello";
        char haystack[1024];
        int i;

        for(i=0;i<sizeof(haystack)-strlen(needle)-1;++i)
        {
                haystack[i]='A'+i%57;
        }
        memcpy(haystack+i,needle, strlen(needle)+1);
        /*printf("%s\n%d\n", haystack, haystack[strlen(haystack)]);*/
        init_stristr();

        for (i=0;i<1000000;++i)
        {
                /*my_stristr(haystack, needle);*/
                strcasestr(haystack,needle);
        }


        return 0;
}

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

#!/bin/bash
function bc_calc()
{
        echo $(echo "scale=4;$1" | bc)
}
time="/usr/bin/time -p"
prog="$1"
accum=0
runs=10
for a in $(jot $runs 1 $runs)
do
        echo -n "run $a... "
        t=$($time $prog 2>&1| grep user | awk '{print $2}')
        echo "time = $t"
        accum=$(bc_calc "$accum+$t")
done

echo -n "average user time over $runs runs = "
echo $(bc_calc "$accum/$runs")
13
ответ дан 4 December 2019 в 07:24
поделиться

Почему делают Вы используете _strlwr (строка); в init_stristr ()? Это не стандартная функция. По-видимому, это для поддержки локали, но поскольку это не стандартно, я просто использовал бы:

char_table[i] = tolower(i);
2
ответ дан 4 December 2019 в 07:24
поделиться

используйте строковый алгоритм повышения. Это является доступным, кросс-платформенным, и только заголовочный файл (никакая библиотека для соединения в). Не говоря уже о том, что необходимо использовать повышение так или иначе.

#include <boost/algorithm/string/find.hpp>

const char* istrstr( const char* haystack, const char* needle )
{
   using namespace boost;
   iterator_range<char*> result = ifind_first( haystack, needle );
   if( result ) return result.begin();

   return NULL;
}
2
ответ дан 4 December 2019 в 07:24
поделиться

Принятие обеих входных строк является уже строчным.

int StringInStringFindFirst(const char* p_cText, const char* p_cSearchText)
{
    int iTextSize = strlen(p_cText);
    int iSearchTextSize = strlen(p_cSearchText);

    char* p_cFound = NULL;

    if(iTextSize >= iSearchTextSize)
    {
        int iCounter = 0;
        while((iCounter + iSearchTextSize) <= iTextSize)
        {
            if(memcmp( (p_cText + iCounter), p_cSearchText, iSearchTextSize) == 0)
                return  iCounter;
            iCounter ++;
        }
    }

    return -1;
}

Вы могли также, пытаться использовать маски..., если, например, большинство строк, которые Вы собираетесь сравнить только, содержит символы от до z, возможно, стоит, чтобы сделать что-то вроде этого.

long GetStringMask(const char* p_cText)
{
    long lMask=0;

    while(*p_cText != '\0')
    {       
        if (*p_cText>='a' && *p_cText<='z')
            lMask = lMask | (1 << (*p_cText - 'a') );
        else if(*p_cText != ' ')
        {
            lMask = 0;
            break;      
        }

        p_cText ++;
    }
    return lMask;
}

Затем...

int main(int argc, char* argv[])
{

    char* p_cText = "this is a test";   
    char* p_cSearchText = "test";

    long lTextMask = GetStringMask(p_cText);
    long lSearchMask = GetStringMask(p_cSearchText);

    int iFoundAt = -1;
    // If Both masks are Valid
    if(lTextMask != 0 && lSearchMask != 0)
    {
        if((lTextMask & lSearchMask) == lSearchMask)
        {       
             iFoundAt = StringInStringFindFirst(p_cText, p_cSearchText);
        }
    }
    else
    {
        iFoundAt = StringInStringFindFirst(p_cText, p_cSearchText);
    }


    return 0;
}
1
ответ дан 4 December 2019 в 07:24
поделиться

Я был бы совет Вы для взятия части общей strcasestr реализации, которая уже существует. Например, бойких, glibc, OpenBSD, FreeBSD, и т.д. Можно искать больше с google.com/codesearch. Можно затем сделать некоторые измерения производительности и сравнить другую реализацию.

1
ответ дан 4 December 2019 в 07:24
поделиться

Если Вы хотите потерять циклы ЦП, Вы могли бы рассмотреть это - давайте предположим, что мы имеем дело с ASCII и не Unicode.

Сделайте статическую таблицу с 256 записями. Каждая запись в таблице составляет 256 битов.

Чтобы протестировать, равны ли два символа, Вы делаете что-то вроде этого:

if (BitLookup(table[char1], char2)) { /* match */ }

Для создания таблицы Вы устанавливаете немного везде в таблице [char1], где Вы считаете это достойным char2. Таким образом в создании таблицы Вы установили бы биты в индексе для и в 'a'th запись (и 'запись A'th).

Теперь это будет достаточно медленным, чтобы сделать разрядный поиск (бит ищут, будет сдвиг, маска и добавит, скорее всего), таким образом, Вы могли использовать вместо этого таблицу байтов, таким образом, Вы используете 8 битов для представления 1 бита. Это возьмет 32K - так ура - Вы поразили компромисс времени/пространства! Мы могли бы хотеть сделать таблицу более гибкой, так скажем, мы делаем это вместо этого - таблица определит соответствия вместо этого.

Два символа считают конгруэнтными, если и только если существует функция, которая определяет их как эквивалентных. Так и конгруэнтного для нечувствительности к регистру. 'À', 'Á' и 'Â' являются конгруэнтными для диакритической нечувствительности.

Таким образом, Вы определяете битовые поля, которые соответствуют Вашим соответствиям

#define kCongruentCase (1 << 0)
#define kCongruentDiacritical (1 << 1)
#define kCongruentVowel (1 << 2)
#define kCongruentConsonant (1 << 3)

Затем Ваш тест - что-то вроде этого:

inline bool CharsAreCongruent(char c1, char c2, unsigned char congruency)
{
    return (_congruencyTable[c1][c2] & congruency) != 0;
}

#define CaseInsensitiveCharEqual(c1, c2) CharsAreCongruent(c1, c2, kCongruentCase)

Этот вид бита, играющего с ginormous таблицами, является основой ctype, кстати.

0
ответ дан 4 December 2019 в 07:24
поделиться

Если можно управлять строкой иглы так, чтобы это всегда было в нижнем регистре, то можно записать измененную версию stristr () для предотвращения поисков для этого и таким образом ускорить код. Это не является столь же общим, но это может быть быстрее - немного быстрее. Подобные комментарии относятся к стогу сена, но Вы, более вероятно, будете читать, стог сена из источников вне Вашего управления для Вас не может быть уверен, что данные отвечают требованию.

Стоит ли усиление в производительности того, другой вопрос в целом. Для 99% приложений ответ "нет, Это не стоит того". Ваше приложение могло бы быть одним из крошечного меньшинства, где это имеет значение. Более вероятно это не.

0
ответ дан 4 December 2019 в 07:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: