Автор | Сообщение |
|
| |
Пост N: 401
Зарегистрирован: 08.07.06
|
|
Отправлено: 05.09.14 16:52. Заголовок: Универсальная функция поиска подстрок в строке
Добрый день. Подскажите пожалуйста "универсальную" функцию поиска. Наподобие: IF ("abc 345" $ MyString) .. ENDIF Т.е. нужен быстрый поиск всех входящих подстрок, разделенных пробелом в любом порядке. Wildcards пока(?) не актуален. Вряд-ли для этого нужно изобретать свой велосипед... Спасибо.
|
|
|
Ответов - 15
[только новые]
|
|
|
| |
Пост N: 4205
Зарегистрирован: 17.05.05
|
|
Отправлено: 05.09.14 17:22. Заголовок: Если я правильно пон..
AT() (HB_AT()) не подходит ? А вообще нужно тестить что быстре $ , HB_WILDMATCH или HB_AT
|
|
|
|
| |
Пост N: 402
Зарегистрирован: 08.07.06
|
|
Отправлено: 05.09.14 20:27. Заголовок: Dima пишет: AT() (H..
Dima пишет: цитата: | AT() (HB_AT()) не подходит ? А вообще нужно тестить что быстре $ , HB_WILDMATCH или HB_AT |
| AT(), HB_AT(), $ - не то... Нужно, к примеру, чтобы поиск по образцу "abc 123" дал TRUE в строке, например, такой: "012345 defabc" HB_WILDMATCH() - ща гляну, спасибо за наводку.
|
|
|
|
| |
Пост N: 4206
Зарегистрирован: 17.05.05
|
|
Отправлено: 05.09.14 20:54. Заголовок: Sergy пишет: Нужно,..
Sergy пишет: цитата: | Нужно, к примеру, чтобы поиск по образцу |
| По образцу смотри регулярные выражения в Harbour , их есть там :)
|
|
|
|
| |
Пост N: 403
Зарегистрирован: 08.07.06
|
|
Отправлено: 05.09.14 21:49. Заголовок: Dima пишет: По обра..
Dima пишет: цитата: | По образцу смотри регулярные выражения в Harbour , их есть там :) |
| Немного не то, что нужно. Как, впрочем и hb_WildMatch(). Суть: есть ассортимент из ~7000 наименований товара. Юзеру нужен "быстрый и удобный" отбор. Набрал он, к примеру в строке поиска "10 SD 32" - ему из всего ассортимента нужно показать только тот товар, который удовлетворяет условию: ("10" $ name) .AND. ("SD" $ name) .AND. ("32 $ name"). Т.е. это флэшки SD или MicroSD емкостью 32гига 10-го класса. C регулярными выражениями никто морочиться не будет - сто пудофф. Максимум может понадобиться выражение "не входит", например: "10 SD 32 !micro" - даст тот-же самый результат, но в него не будут включены карты типа microSD - только SD. Пока наваял такое: FUNC MatchIn(cPattern,cText) // поиск по набору подстрок LOCAL result,i,num_words,x num_words := NUMTOKEN(cPattern," ") // считаем кол-во слов IF num_words > 1 // сложный поиск ? result := TRUE // заранее FOR i:=1 TO num_words x := TOKEN(cPattern," ",i) // разбираем по словам IF (LEFT(x,1) $ "!~") // отрицание - то, чего быть не должно IF (SUBSTR(x,2) $ cText) // убираем первый символ result := FALSE EXIT ENDIF ELSE // обычная строка, которую ищем IF !(x $ cText) result := FALSE EXIT ENDIF ENDIF NEXT i ELSE // поиск по одному слову result := (cPattern $ cText) ENDIF RETURN result Но чую, что это велосипед, причем не самый быстрый...
|
|
|
|
| |
Пост N: 4207
Зарегистрирован: 17.05.05
|
|
Отправлено: 05.09.14 23:17. Заголовок: во во тоже хотел с т..
во во тоже хотел с токенами предложить.
|
|
|
|
| постоянный участник
|
Пост N: 406
Зарегистрирован: 17.02.12
|
|
Отправлено: 06.09.14 11:53. Заголовок: Sergy А если так: ..
Sergy А если так: cString := ... // где ищем cToken := "10 SD 32" // что ищем ... aToken := hb_aTokens(cToken, ' ') nToken := len(aToken) FOR i := 1 TO nToken lFound := aToken[ i ] $ cString IF lFound EXIT ENDIF NEXT IF lFound // нашли ... ENDIF
|
|
|
|
| постоянный участник
|
Пост N: 3615
Зарегистрирован: 12.09.06
|
|
Отправлено: 06.09.14 14:48. Заголовок: Sergy пишет: в стро..
Sergy пишет: цитата: | в строке поиска "10 SD 32" - ему из всего ассортимента нужно показать только тот товар, который удовлетворяет условию: ("10" $ name) .AND. ("SD" $ name) .AND. ("32 $ name") |
| Я делаю такие поиски через условную индексацию. На базе в 10 тыс.записей меньше минуты, а то и меньше. Если держать открытым индекс по полю name то вообще будет мухой летать. Вот например такое условное выражение: DateDog>CTOD('01.01.10') .AND.KStDogov=1.AND.KVidOpl=3.AND.KFirma=31.AND.Kcity=1.AND.!DELETED()
|
|
|
|
| |
Пост N: 163
Зарегистрирован: 03.12.08
|
|
Отправлено: 06.09.14 21:35. Заголовок: Будете ржать , мой п..
Будете ржать , мой поиск на базе в 10 тыс наименований (несколько текстовых полей для поиска всех вхождений на локальной базе) занимает меньче чем пол секунды : Используем конечно токены :) сверхбыстрый поиск ! -> Достаточно построить таблицу хотя-бы с одним из фрагментов . А далее по рекурсии по вхождению остальных фрагментов поиска ..... PS: Пост # 406 именно так !
|
|
|
|
| постоянный участник
|
Пост N: 3616
Зарегистрирован: 12.09.06
|
|
Отправлено: 06.09.14 21:45. Заголовок: Softlog86 пишет: вх..
Softlog86 пишет: цитата: | вхождений на локальной базе) занимает меньче чем пол секунды |
| А у меня поиск по сетевой базе.
|
|
|
|
| |
Пост N: 404
Зарегистрирован: 08.07.06
|
|
Отправлено: 07.09.14 21:44. Заголовок: SergKis пишет: Serg..
SergKis пишет: цитата: | Sergy А если так: aToken := hb_aTokens(cToken, ' ') ... |
| Ок, спасибо за наводку, ща посмотрю, что это за зверь...
|
|
|
|
| |
Пост N: 405
Зарегистрирован: 08.07.06
|
|
Отправлено: 07.09.14 21:46. Заголовок: Andrey пишет: Я дел..
Andrey пишет: цитата: | Я делаю такие поиски через условную индексацию. На базе в 10 тыс.записей меньше минуты, а то и меньше. Если держать открытым индекс по полю name то вообще будет мухой летать. Вот например такое условное выражение: DateDog>CTOD('01.01.10') .AND.KStDogov=1.AND.KVidOpl=3.AND.KFirma=31.AND.Kcity=1.AND.!DELETED() |
| Понимаете, какая петрушка: сейчас оператору нужна флэшка на 32гига класс10, а потом он посмотрел на них, нажал Esc(отмена) или Enter(выбор) и дальше хочет найти на 16гигов. Или класс 6. Или вообще не флэшку, а кулер для проца. Вариант перестраивать индекс "меньше минуты" в такой ситуации - вообще не вариант...
|
|
|
|
|
| |
Пост N: 406
Зарегистрирован: 08.07.06
|
|
Отправлено: 07.09.14 21:47. Заголовок: Softlog86 пишет: Бу..
Softlog86 пишет: цитата: | Будете ржать , мой поиск на базе в 10 тыс наименований (несколько текстовых полей для поиска всех вхождений на локальной базе) занимает меньче чем пол секунды : Используем конечно токены :) сверхбыстрый поиск ! -> Достаточно построить таблицу хотя-бы с одним из фрагментов . А далее по рекурсии по вхождению остальных фрагментов поиска ..... PS: Пост # 406 именно так ! |
| Сорри, можно чуть более развернуто - про "таблицу с одним из фрагментов и рекурсией" ? И где этот пост №406 ?? Спасибо
|
|
|
|
| постоянный участник
|
Пост N: 408
Зарегистрирован: 17.02.12
|
|
Отправлено: 08.09.14 09:22. Заголовок: Sergy вместо aToken..
Sergy вместо aToken[ i ] $ cString можно попробовать: AT(aToken[ i ], @cString) > 0 или hb_at(aToken[ i ], @cString) > 0
|
|
|
|
| |
Пост N: 407
Зарегистрирован: 08.07.06
|
|
Отправлено: 08.09.14 21:27. Заголовок: SergKis пишет: вмес..
SergKis пишет: цитата: | вместо aToken[ i ] $ cString можно попробовать: AT(aToken[ i ], @cString) > 0 или hb_at(aToken[ i ], @cString) > 0 |
| Либо я чего-то не понимаю, либо операция "x $ y" оказывается самой быстрой: FUNC Main() LOCAL start,i,sx,x,t1,t2,t3,counter counter := 10000000 sx := "A simply string we use to determine the speed of operations" start := HB_MILLISECONDS() FOR i:=1 TO counter x := AT("of",sx) NEXT i t1 := HB_MILLISECONDS() - start start := HB_MILLISECONDS() FOR i:=1 TO counter x := ("of" $ sx) NEXT i t2 := HB_MILLISECONDS() - start start := HB_MILLISECONDS() FOR i:=1 TO counter x := HB_AT("of",sx) NEXT i t3 := HB_MILLISECONDS() - start ? "Test AT() : ",STR(t1/1000),"sec" ? "Test $ : ",STR(t2/1000),"sec" ? "Test HB_AT() : ",STR(t3/1000),"sec" INKEY(0) дает результат: Test AT() : 2.31 sec Test $ : 1.39 sec Test HB_AT() : 2.08 sec 10 миллионов операций за полторы секунды - думаю, тут нечего больше оптимизировать...
|
|
|
|
| |
Пост N: 164
Зарегистрирован: 03.12.08
|
|
Отправлено: 09.09.14 11:00. Заголовок: Sergy тут видимо обс..
Sergy тут видимо обсуждаем как сделать поиск по вхождению нескольких фрагментов в файле базы данных .... а не поиск в памяти .... Первичная подготовка : SELECT SPISOK // наша база данных hs := HS_INDEX( "SPISOK","UPPER(CHARREM('-., ',TYPE+' '+COMMENT))" , 2, 0, , .T., 3 ) // Создаём Индекс по ДВУМ ТЕКСТОВЫМ ПОЛЯМ : TYPE + COMMENT // Предварительно удаляя символы -разделители >[ - . , ] Поиск фрагментов : SEARCH - это DBF-файл куда сбрасываем строки с найденными фрагментами (для дальнейшего просмотра) перед поиском - она пустая USE SEARCH NEW ALIAS SEARCH EXCLUSIVE SELECT SPISOK aTokens := HB_ATokens( MySTR, ' ' ) // в массиве aTOKENS - минифразы из общей строки (MySTR) - Разделитель ПРОБЕЛ // // По сути - значения по первому токену - далее идёт отфильтровывание записей в которых нет всех следующих // токенов . За тем пакуем данные и на выходе только строки со всеми вхождениями ! MyStrA:=UPPER(CHARREM('.,-',aTOKENS[1])) // Поиск первой фразы из токена 1 - записываем в выходной файл поисковика! HS_SET( hs, MySTRA ) // Ищем первый фрагмент в индексном файле GO TOP while ( n := HS_NEXT( hs ) ) > 0 dbgoto( n ) if HS_VERIFY( hs ) > 0 // Искомое найдено !!! Переписываем в результирующий файл SEARCH->(DBAPPEND()) REPLACE SEARCH->CODE WITH SPISOK->CODE REPLACE SEARCH->TYPE WITH SPISOK->TYPE REPLACE SEARCH->COMMENT WITH SPISOK->COMMENT endif enddo IF LEN(aTOKENS)>1 && Токенов больше чем 1 SELECT SEARCH GO TOP For i:=2 TO LEN(aTOKENS) // Для каждого элемента массива aTokens после первого cElem:=UPPER(CHARREM('.,-',aTOKENS)) // убираем ненужные символы GO TOP DO WHILE !EOF() // Проверяем на 'X' в вырезанных от ненужных символов строках "TYPE" + "COMMENT" K:= UPPER(CHARREM('.,-',SEARCH->TYPE+" "+SEARCH->COMMENT+" "+CHARREM(' ',SEARCH->OEM))) If (cElem $ K ) // Ничего не делаем ELSE DELETE // cELEM нет ни в одном из полей ! ENDIF SKIP ENDDO Next // Следующий токен для поиска в SEARCH.DBF PACK // Упаковываем SEARCH.DBF ENDIF SELECT SEARCH // << Теперь здесь находятся строки в которых есть ВСЕ ИСКОМЫЕ ФРАЗЫ
|
|
|
|