Найти соответствие в строке

Young <

Now, finally free
Сообщения
1,263
Реакции
505
Допустим, пример:

C-подобный:
static const char str[] = "привет 1;привет;прив";

char mystr[] = "прив";

if(FoundInString(mystr, str))
    //Нашел

Т.е. в чем трудность.
Нужно чтобы строка mystr нашлась в строке str именно в промежутке от ; до ; , или до конца (проще говоря, разделить с помощью ; , без реагирования на совпадение "прив" в "привет 1" и "привет")

Как можно реализовать такую функцию (FoundInString) ?
 
Решение
Допустим, пример:

C-подобный:
static const char str[] = "привет 1;привет;прив";

char mystr[] = "прив";

if(FoundInString(mystr, str))
    //Нашел

Т.е. в чем трудность.
Нужно чтобы строка mystr нашлась в строке str именно в промежутке от ; до ; , или до конца (проще говоря, разделить с помощью ; , без реагирования на совпадение "прив" в "привет 1" и "привет")

Как можно реализовать такую функцию (FoundInString) ?

Как вариант, вернет конкретно позицию 2-го value:
C-подобный:
char sBuffer[64] = "value;value2;value3";
int iPos = FindInSlice(sBuffer, "value", 5, 10);

int FindInSlice(const char[] sBuffer, const char[] sFind, int iStart, int iEnd){
    iStart = StrContains(sBuffer[iStart], sFind, true)+iStart;
    if(iEnd <= iStart){...

RudikS

Участник
Сообщения
130
Реакции
61
Допустим, пример:

C-подобный:
static const char str[] = "привет 1;привет;прив";

char mystr[] = "прив";

if(FoundInString(mystr, str))
    //Нашел

Т.е. в чем трудность.
Нужно чтобы строка mystr нашлась в строке str именно в промежутке от ; до ; , или до конца (проще говоря, разделить с помощью ; , без реагирования на совпадение "прив" в "привет 1" и "привет")

Как можно реализовать такую функцию (FoundInString) ?
Не самая лучшая реализация, но вроде работает.
C-подобный:
int FindChar(char [] str, int strLen, char symb)
{
    for (int i = 0; i < strLen; i++)
    {
        if (str[i] == symb)
        {
            return i;
        }
    }

    return -1;
}

bool FindInString(char [] str, int strLen, char [] pattern, int patternLen)
{
    int index = 0, offset = 0, endIndex = 0;
    do
    {
        index = FindChar(str + endIndex, strLen - endIndex, ';');
        if (index == -1)
        {
            return false;
        }

        index += endIndex + 1;

        offset = index + patternLen;

        if (offset >= strLen)
        {
            return false;
        }

        endIndex = FindChar(str + offset, strLen - offset, ';');

        if (endIndex == -1)
        {
            return false;
        }

        endIndex += offset;

        for (int i = index, j = 0; i < endIndex; i++)
        {
            if (str[i] == pattern[j])
            {
                j++;
            }
            else
            {
                j = 0;
            }

            if (patternLen == j)
            {
                return true;
            }
        }
    }
    while (endIndex < strLen);

    return false;
}
 
Последнее редактирование:

Reiko1231

AlexTheRegent
Сообщения
508
Реакции
1,335
Можно сделать через регулярное выражение \b(?:^|;)прив(?:;|\z)

\b - начало слова
() - один из перечисленных внутри символов
?: - не делать группу захвата
^|; - начало строки или символ ;
прив - искомое слово
() - один из перечисленных внутри символов
?: - не делать группу захвата
;|\z - символ ; или конца ввода

Чтобы его использовать, сначала нужно скомпилировать регулярное выражение с помощью Regex.Regex (с флагом PCRE_UTF8, если нужна поддержка русских символов), затем проверить строку с помощью Regex.Match. Если будет возвращён ноль, то слово не найдено; если минус один то значит ошибка (хотя я проверял это регулярное выражение); во всех остальных случаях слово было найдено (возвращённое функцией число) раз.

Edited. Добавлена проверка, что перед найденным словом нет предыдущего слова, чтобы не реагировать на вхождения типа ;текст прив;
 
Последнее редактирование:

Someone

Участник
Сообщения
1,933
Реакции
1,653
Допустим, пример:

C-подобный:
static const char str[] = "привет 1;привет;прив";

char mystr[] = "прив";

if(FoundInString(mystr, str))
    //Нашел

Т.е. в чем трудность.
Нужно чтобы строка mystr нашлась в строке str именно в промежутке от ; до ; , или до конца (проще говоря, разделить с помощью ; , без реагирования на совпадение "прив" в "привет 1" и "привет")

Как можно реализовать такую функцию (FoundInString) ?

Как вариант, вернет конкретно позицию 2-го value:
C-подобный:
char sBuffer[64] = "value;value2;value3";
int iPos = FindInSlice(sBuffer, "value", 5, 10);

int FindInSlice(const char[] sBuffer, const char[] sFind, int iStart, int iEnd){
    iStart = StrContains(sBuffer[iStart], sFind, true)+iStart;
    if(iEnd <= iStart){
        return -1;
    }
    return iStart;
}

Вариант с разбивкой всей строки:
C-подобный:
char sText[256] = "test1;test2;test3;test4";
int iDelimCount, iDelimLastPos;
for(int i; i < sizeof(sText); i++){
    if(sText[i] == ';'){
        iDelimCount++;
        iDelimLastPos = i;
    }
}

iDelimLastPos++;
if(iDelimLastPos > sizeof(sText) || sText[iDelimLastPos] == 0){
    iDelimCount--;
}

if(iDelimCount > 0){
    iDelimCount++;
    char[][] sData = new char[iDelimCount][PART_MAX_LEN];
    ExplodeString(sText, ";", sData, iDelimCount, PART_MAX_LEN)

    // в sData разбитая строка
}else{
    // в sText нет разделителей
}
 
Решение

rejchev

менеджер клоунов
Сообщения
1,669
Реакции
1,291
@Young <
Поиск слова по полному совпадению внутри строки, если в этом была суть.
Отрабатывает довольно быстро на фоне перебора из 1000 слов в контейнере, в окружении чата, но сам по себе метод устарел...
Вырезка метода из GFilters:
C-подобный:
// На входе:
// Контейнер со словами, которые нужно найти в строке
// Автор сообщения
// Символ побайтовой замены найденного слова
// Буфер и его размер
public void CheckOnBW(ArrayList aContainer, int iClient, int iSymbol, char[] buffer, int iLen)
{
    static int iIndex, iPos;
    static char
        szBuffer[PMP],          // Временное хранилище значения на входе
        szPhrase[PMP],          // Хранилище для фраз из контейнера
        szPoscorrect[PMP];      // Хранилище содержимого при корректировки значения
    
    strcopy(SZ(szBuffer), buffer);

    static Regex hRegex;
    if(!hRegex){
        hRegex = CompileRegex("[^a-zA-Z0-9а-яА-Я_]", PCRE_UTF8);
    }
    

    for(int i; i < aContainer.Length; i++)
    {
        aContainer.GetString(i, SZ(szPhrase));

        // Удостоверимся, что это имеет смысл
        if(!szPhrase[0])
            continue;
        
        // В данном случае, а именно в GFilters, фильтр по полному совпадению осуществляется со знаком '~'
        // Поэтому, учитываем смещение и получаем вхождение, если оно есть
        if(szPhrase[0] == '~' && (iIndex = UTF8StrContains(szBuffer, szPhrase[1], false)) != -1)     
        {
            // Копируем нашу строку в буффер для корректировки
            strcopy(SZ(szPoscorrect), szBuffer);

            /*
                Ищем начало нашего слова.
                Поскольку мы ищем лишь слова с полным совпадением, то нам необходимо убедиться, что
                Первое вхождение и есть начало нашего слова.
            */
            SearchStart(hRegex, iIndex, SZ(szPoscorrect));

            // Ищем конец нашего слова.
            SearchEnd(hRegex, iIndex, szPoscorrect);
            
            
            /*
                Заменяем его побайтово.

                В условии нужно учитывать смещение согласно синтаксису GFilters, т.к. szPhrase[0] = '~'

                По поводу кастомной функции:
                * Её нет в стд либе UTF-8-string.
                * Стд функция ReplaceString() имеет теже проблемы, что и функции, которые исправлены в UTF-8-string
                * Функция неменого изменена
            */
            if(UTF8StrEqual(szPhrase[1], szPoscorrect, false)){
                UTF8ReplaceString(SZ(szBuffer), szPhrase[1], iSymbol);                   
            }
                
        }
    }
        
    // Проверка последовательности.
    if(!UTF8strcmp(szBuffer, buffer, false)){
        return;
    }

    // Заполняем основной буффер на выход
    strcopy(buffer, iLen, szBuffer);
}

// Вход:
// Регеx выражение
// Позиция совпадения
// Строка целиком и ее размер
void SearchStart(Regex &hLocal, int &iPointer, char[] szPhrase, int iLen)
{
    // Вектор движения: 0 <- iPointer

    // Не имеет смысла, если позиция уже 0
    if(!iPointer)
        return;

    // Ищем количество совпадений по регексу
    static int iMatchCount;
    iMatchCount = hLocal.MatchAll(szPhrase);

    // Если таковых нет, то это одно большое слово или несколько: один два три -> одиндватри
    if(iMatchCount < 1)
    {
        iPointer = 0;
        return;
    }
    
    // Перебор
    for(int i; i < iMatchCount; i++)
    {
        /*
            Немного на тему, как работает MatchOffset:
                Данный метод возвращает смещение конца найденного выражения.
        */
        if(hLocal.MatchOffset(i) > iPointer)
        {

            /*
                Согласно условию выше сдвигаем вхождение
            */
            iPointer = (!i) ? 0 : hLocal.MatchOffset(i-1);
            break;
        }
    }

    // Сохраняем наши достижения
    strcopy(szPhrase, iLen, szPhrase[iPointer]);
}

// Вход:
// Регеx выражение
// Позиция вхождения
// Буффер
void SearchEnd(Regex &hLocal, int &iPointer, char[] szPhrase)
{
    // В целом, действия повторяются
    static int iMatchCount;
    iMatchCount = hLocal.MatchAll(szPhrase);

    // Отсутствие совпадений по выражению, конец = длине строки.
    // В ином случае, это первое совпадение с оффсетом - 1.
    if(iMatchCount < 1)
        iPointer = strlen(szPhrase);

    else iPointer = hLocal.MatchOffset(0) - 1;

    // Обрываем
    szPhrase[iPointer] = 0;
}
 

Kailo

Участник
Сообщения
194
Реакции
896
Аргумент len сделан в оптимизационных целях, если размер строки уже известен.
C-подобный:
bool FoundInString(const char[] str, const char[] substr, int len=0, bool caseSensitive=true)
{
    if (!len && !(len = strlen(substr)))
        return false;
    int pos = 0, off;
    bool cond;
    while ((off = StrContains(str[pos], substr, caseSensitive)) != -1)
    {
        cond = !(pos += off) || str[pos-1] == ';';
        pos += len;
        if (cond && (!(off = str[pos]) || off == ';'))
            return true;
    }
    return false;
}
 
Сверху Снизу