Сравнение по маске '*MA?K*'

Тема в разделе "WASM.BEGINNERS", создана пользователем Android, 18 фев 2006.

  1. Android

    Android New Member

    Публикаций:
    0
    Регистрация:
    24 авг 2003
    Сообщения:
    183
    Адрес:
    Ukraine
    Есть ли в Windows стандартная функция кторая сравнивает строку по маске, например, '*asd?*ншгншг*'.

    * - любая последовательность символов

    ? - один символ
     
  2. Android

    Android New Member

    Публикаций:
    0
    Регистрация:
    24 авг 2003
    Сообщения:
    183
    Адрес:
    Ukraine
    Нет какого апи что ли?
     
  3. Vasil

    Vasil Василь

    Публикаций:
    0
    Регистрация:
    7 янв 2006
    Сообщения:
    228
    Адрес:
    Ижевск
    Напиши сам на ASMе, всё равно будет работать быстрее, чем API. Ничего сложного в твоей проблеме нет...
     
  4. Android

    Android New Member

    Публикаций:
    0
    Регистрация:
    24 авг 2003
    Сообщения:
    183
    Адрес:
    Ukraine
    Я реализовал, занимает 776 байт, юникод, аски, без учета регистра, но в проекте каждый байт на счету. Думаю если есть уже стандартная можно ее юзать.
     
  5. Vasil

    Vasil Василь

    Публикаций:
    0
    Регистрация:
    7 янв 2006
    Сообщения:
    228
    Адрес:
    Ижевск
    Ну тогда не знаю, чем помочь. Копай SDK.



    А вообще что-то многовато 776 байт. Я понял тебе скорость не важна. Используй более короткие команды и больше регистров.
     
  6. crypto

    crypto Active Member

    Публикаций:
    0
    Регистрация:
    13 дек 2005
    Сообщения:
    2.533
    bool TestString(char* Your_String)

    {

    char *p;

    p = strstr(Your_String, "asd");

    if (p && strstr(p + 4, "ншгншг")) return true;

    return false;

    }
     
  7. Android

    Android New Member

    Публикаций:
    0
    Регистрация:
    24 авг 2003
    Сообщения:
    183
    Адрес:
    Ukraine
    crypto

    неееет... мне нужен универсальный метод)))))



    Vasil

    А вообще что-то многовато 776 байт. Я понял тебе скорость не важна. Используй более короткие команды и больше регистров.



    я выбрал что-то среднне по размеру и скорости, т.к. скорость тоже не маловажна, в модуле есть еще сопутствующие функции, а TestMask 170 байт + 256 байт матрица сравнений. В любом случае эта апи есть, ведь FindFirstFile использует ее.
     
  8. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257




    Наверное тебе нужен готовый код?

    То, что предложил crypto, надо чуть доработать и всё.
     
  9. Android

    Android New Member

    Публикаций:
    0
    Регистрация:
    24 авг 2003
    Сообщения:
    183
    Адрес:
    Ukraine
    "Наверное тебе нужен готовый код?

    То, что предложил crypto, надо чуть доработать и всё."


    Мое решение меня вполне устраивает, оно тоже основывается на поиске подстроки.
     
  10. Android

    Android New Member

    Публикаций:
    0
    Регистрация:
    24 авг 2003
    Сообщения:
    183
    Адрес:
    Ukraine
    Если найду эту апи - буду ее применять.
     
  11. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Можешь поискать эту таинственную апи внутри FindFirstFileExW :)))
     
  12. Android

    Android New Member

    Публикаций:
    0
    Регистрация:
    24 авг 2003
    Сообщения:
    183
    Адрес:
    Ukraine
    cresta

    если знаешь - скажи
     
  13. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Android

    Дык нету там ничего. В смысле какой-либо спец. функции, проверяющей совпадение маски. Из апи только RtlUnicodeStringToAnsiString, RtlAnsiStringToUnicodeString, RtlInitUnicodeString, RtlInitAnsiString, NtOpenFile
     
  14. Android

    Android New Member

    Публикаций:
    0
    Регистрация:
    24 авг 2003
    Сообщения:
    183
    Адрес:
    Ukraine
    Я смотрел перед тем как давать пост, тоже ничего не нашел. Скорее всего она не експортируется никакой библиотекой, просто в каокй-то базовой процедуре реалезован этот алгоритм .
     
  15. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Вот тебе 490 байт, оптимизированные на скорость:


    Код (Text):
    1. //===============================================================
    2. BOOL mask_search(char* Str, char* maskStr){
    3.     char    array[1024];
    4.     char*   offset = Str;
    5.     int        i=0;
    6.  
    7.     while ( *((char*)maskStr) =='*' ) maskStr++;
    8.     do{
    9.         if ( '*' == (array[i] = maskStr[i]) ) array[i]=0;
    10.     }while (maskStr[i++]);
    11.     array[i]=0; i=0;
    12.  
    13.     while ( *((short*) &array[i]) ){
    14.         if ( 0 == (offset = strstr(offset, &array[i]))) return FALSE;
    15.         while ( array[i] ){
    16.             i++;
    17.             offset++;
    18.         }
    19.         i++;
    20.     }
    21.     return TRUE;
    22. }
    23.  






    Компилируй и выдирай код.

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

    Тут основная масса кода - это strstr. Её можно и самому нарисовать, чтобы поменьше было.
     
  16. SDragon

    SDragon New Member

    Публикаций:
    0
    Регистрация:
    6 июн 2005
    Сообщения:
    133
    Адрес:
    Siberia
    Из старой библиотеки Snippets:


    Код (Text):
    1. static Boolean_T PASCAL patimat (const char *pat, const char *str)
    2. {
    3.       switch (*pat)
    4.       {
    5.       case '\0':
    6.             return !*str;
    7.  
    8.       case '*' :
    9.             return patimat(pat+1, str) || *str && patimat(pat, str+1);
    10.  
    11.       case '?' :
    12.             return *str && patimat(pat+1, str+1);
    13.  
    14.       default  :
    15.             return (toupper(*pat) == toupper(*str)) && patimat(pat+1, str+1);
    16.       }
    17. }




    Очень просто, но медленно. В случаях case '?' и default хвостовую рекурсию можно легко оптимизировать, превратив в цикл.



    Мой вариант (оптимизирован по скорости; будучи откомпилированным VC++, занимает 169 байт + можно еще оптимизировать по размеру):


    Код (Text):
    1. static bool CheckMask(TCHAR* fn, TCHAR* mask) { // Соответствует ли имя файла маске?
    2.     while(*mask) {
    3.         if(*mask == '?') {
    4.             mask++; if(*fn) fn++;
    5.         }
    6.         else if(*mask == '*') {
    7.             mask++;
    8.             while(*mask == '*' || *mask == '?') // ** эквивалентно *, а *? будем
    9.                 mask++;                         // считать эквивалентным *
    10.             if(!*mask) // Звездочка в конце маски всегда совпадает
    11.                 return true;
    12.             TCHAR* end = mask;
    13.             // Продвинуться до конца сегмента, не содержащего * и ?
    14.             while(*end != '*' && *end != '?' && *end != '\0')
    15.                 end++;
    16.             while(*fn != *mask || memcmp(fn, mask, size_t((BYTE*)end - (BYTE*)mask))) {
    17.                 if(!*fn)          // В маске после звездочки есть символ,
    18.                     return false; // а в строке такого символа нет
    19.                 fn++;
    20.             }
    21.             fn += size_t(end - mask); mask = end;
    22.         }
    23.         else {
    24.             if(*mask != *fn)
    25.                 return false;
    26.             mask++; fn++;
    27.         }
    28.     }
    29.     return !*fn;
    30. }
    31.  
    32. void TestCheckMask() {
    33.     assert(CheckMask(_T("index.html"), _T("index.html")) == true);
    34.     assert(CheckMask(_T("index.htm"), _T("index.html")) == false);
    35.     assert(CheckMask(_T("text.txt"), _T("*.txt")) == true);
    36.     assert(CheckMask(_T("lrmark.txt"), _T("lr*")) == true);
    37.     assert(CheckMask(_T("soso.txt"), _T("so*so*.txt")) == true);
    38.     assert(CheckMask(_T("solsol.txt"), _T("so*so*.txt")) == true);
    39.     assert(CheckMask(_T("lssol.txt"), _T("*so*.txt")) == true);
    40.     assert(CheckMask(_T("index.html"), _T("*.htm*")) == true);
    41.     assert(CheckMask(_T("index.html"), _T("*.htm?")) == true);
    42.     assert(CheckMask(_T("index.htm"), _T("*.htm?")) == true);
    43.     assert(CheckMask(_T("index.htm"), _T("*.htm*")) == true);
    44.     assert(CheckMask(_T("index.htm"), _T("*x.htm*")) == true);
    45.     assert(CheckMask(_T("index.txt"), _T("index.*l")) == false);
    46.     assert(CheckMask(_T("skynet.exe"), _T("sky???.exe")) == true);
    47.     assert(CheckMask(_T("skynet.exe"), _T("sky??.exe")) == false);
    48.     assert(CheckMask(_T("skynet.exe"), _T("sky????.exe")) == false);
    49.     assert(CheckMask(_T("index.html"), _T("")) == false);
    50.     assert(CheckMask(_T(""), _T("index.html")) == false);
    51.     assert(CheckMask(_T(""), _T("")) == true);
    52. }
     
  17. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    SDragon



    CheckMask("eeeasdghjнгш", "asd*нгш*") ?
     
  18. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    167 байт :)


    Код (Text):
    1. //===============================================================
    2. __forceinline char* _stdcall _str_str (char* str1, char* str2){
    3.    
    4.     while ( *str1 ){
    5.         char*   cur1=str1;
    6.         char*   cur2=str2;
    7.         while ( (*cur1 == *cur2) || (*cur2 == '?') ){
    8.             cur1++; cur2++;
    9.             if ( ! *cur2 ) return str1;
    10.         }
    11.         if ( ! *cur1 ) return 0;
    12.         str1++;
    13.     }
    14.     return 0;
    15. }
    16.  
    17. //===============================================================
    18. BOOL __stdcall mask_search (char* Str, char* maskStr){
    19.     char    array[1024];
    20.     char*   offset = Str;
    21.     int     i=0;
    22.  
    23.     while ( *((char*)maskStr) =='*' ) maskStr++;
    24.     do{
    25.         if ( '*' == (array[i] = maskStr[i]) ) array[i]=0;
    26.     }while (maskStr[i++]);
    27.     array[i]=0; i=0;
    28.  
    29.     while ( *((short*) &array[i]) ){
    30.         if ( 0 == (offset = _str_str(offset, &array[i]))) return FALSE;
    31.         while ( array[i] ){
    32.             i++;
    33.             offset++;
    34.         }
    35.         i++;
    36.     }
    37.     return TRUE;
    38. }
    39.  
    40.  
    41. //////////////
    42. mask_search ("eeeasdghjнгш", "??as?*?гш*");
     
  19. SDragon

    SDragon New Member

    Публикаций:
    0
    Регистрация:
    6 июн 2005
    Сообщения:
    133
    Адрес:
    Siberia
    cresta
    Код (Text):
    1. CheckMask("eeeasdghjнгш", "asd*нгш*")


    false, ясен пень! Если поставишь звездочку в начале, будет true:
    Код (Text):
    1. CheckMask("eeeasdghjнгш", "*asd*нгш*")




    Проверь, пожалуйста, этот вариант:
    Код (Text):
    1. assert(mask_search("index.html", "") == false);


    На остальных тестах твоя функция работает отлично. Плюс еще одно замечание: вместо
    Код (Text):
    1. array[i]=0; i=0;
    следует написать
    Код (Text):
    1. array[i]=0; array[i+1]=0; i=0;


    Ведь массив не обязательно будет инициализирован нулевыми значениями в начале. Например, в Debug-версии VC++ он инициализируется значениями 0xCC, а в Release-версии на стеке будут случайные значения, оставшиеся от вызова предыдущей функции.
     
  20. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    SDragon

    Пардон, что-то со звездочкой я забыл :)

    [deleted]

    Массив можно завершить двойным нулём иначе.

    Если в качестве строки может передаваться "", то тогда добавляется условие на входе:


    Код (Text):
    1. //===============================================================
    2. BOOL __stdcall mask_search(char* Str, char* maskStr){
    3.     char        array[1024];
    4.     char*       offset = Str;
    5.     int         i=0;
    6.  
    7.     if ( !*maskStr ) return FALSE;    //проверка на пустую строку
    8.     while ( *((char*)maskStr) =='*' ) maskStr++;
    9.     do{
    10.         if ( '*' == (array[i] = maskStr[i]) ) array[i]=0;
    11.     }while (maskStr[i++]);
    12.     *((short*) &array[i])=0; i=0;
    13.  
    14.     while ( *((short*) &array[i]) ){
    15.         if ( 0 == (offset = _str_str(offset, &array[i]))) return FALSE;
    16.         while ( array[i] ){
    17.             i++;
    18.             offset++;
    19.         }
    20.         i++;
    21.     }
    22.     return TRUE;
    23. }