On-line: alex_II, Andrey, i3t4j6, SergKis, гостей 1. Всего: 5 [подробнее..]
АвторСообщение





Пост N: 401
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 05.09.14 16:52. Заголовок: Универсальная функция поиска подстрок в строке


Добрый день.

Подскажите пожалуйста "универсальную" функцию поиска. Наподобие:

IF ("abc 345" $ MyString)
..
ENDIF

Т.е. нужен быстрый поиск всех входящих подстрок, разделенных пробелом в любом порядке. Wildcards пока(?) не актуален.

Вряд-ли для этого нужно изобретать свой велосипед...

Спасибо.

Спасибо: 0 
ПрофильЦитата Ответить
Ответов - 15 [только новые]


администратор




Пост N: 4205
Зарегистрирован: 17.05.05
ссылка на сообщение  Отправлено: 05.09.14 17:22. Заголовок: Если я правильно пон..


AT() (HB_AT()) не подходит ?

А вообще нужно тестить что быстре $ , HB_WILDMATCH или HB_AT

Спасибо: 0 
ПрофильЦитата Ответить





Пост 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() - ща гляну, спасибо за наводку.

Спасибо: 0 
ПрофильЦитата Ответить
администратор




Пост N: 4206
Зарегистрирован: 17.05.05
ссылка на сообщение  Отправлено: 05.09.14 20:54. Заголовок: Sergy пишет: Нужно,..


Sergy пишет:

 цитата:
Нужно, к примеру, чтобы поиск по образцу


По образцу смотри регулярные выражения в Harbour , их есть там :)

Спасибо: 0 
ПрофильЦитата Ответить





Пост 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


Но чую, что это велосипед, причем не самый быстрый...

Спасибо: 0 
ПрофильЦитата Ответить
администратор




Пост N: 4207
Зарегистрирован: 17.05.05
ссылка на сообщение  Отправлено: 05.09.14 23:17. Заголовок: во во тоже хотел с т..


во во тоже хотел с токенами предложить.

Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник




Пост 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


Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник




Пост 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()


Спасибо: 0 
ПрофильЦитата Ответить



Пост N: 163
Зарегистрирован: 03.12.08
ссылка на сообщение  Отправлено: 06.09.14 21:35. Заголовок: Будете ржать , мой п..


Будете ржать , мой поиск на базе в 10 тыс наименований (несколько текстовых полей для поиска всех вхождений на локальной базе) занимает меньче чем пол секунды :
Используем конечно токены :) сверхбыстрый поиск ! -> Достаточно построить таблицу хотя-бы с одним из фрагментов . А далее по рекурсии по вхождению остальных фрагментов поиска .....

PS: Пост # 406 именно так !


Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник




Пост N: 3616
Зарегистрирован: 12.09.06
ссылка на сообщение  Отправлено: 06.09.14 21:45. Заголовок: Softlog86 пишет: вх..


Softlog86 пишет:

 цитата:
вхождений на локальной базе) занимает меньче чем пол секунды


А у меня поиск по сетевой базе.

Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 404
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 07.09.14 21:44. Заголовок: SergKis пишет: Serg..


SergKis пишет:

 цитата:
Sergy
А если так:

aToken := hb_aTokens(cToken, ' ')
...



Ок, спасибо за наводку, ща посмотрю, что это за зверь...

Спасибо: 0 
ПрофильЦитата Ответить





Пост 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. Или вообще не флэшку, а кулер для проца.

Вариант перестраивать индекс "меньше минуты" в такой ситуации - вообще не вариант...

Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 406
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 07.09.14 21:47. Заголовок: Softlog86 пишет: Бу..


Softlog86 пишет:

 цитата:
Будете ржать , мой поиск на базе в 10 тыс наименований (несколько текстовых полей для поиска всех вхождений на локальной базе) занимает меньче чем пол секунды :
Используем конечно токены :) сверхбыстрый поиск ! -> Достаточно построить таблицу хотя-бы с одним из фрагментов . А далее по рекурсии по вхождению остальных фрагментов поиска .....

PS: Пост # 406 именно так !



Сорри, можно чуть более развернуто - про "таблицу с одним из фрагментов и рекурсией" ?
И где этот пост №406 ??

Спасибо

Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник




Пост 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

Спасибо: 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 миллионов операций за полторы секунды - думаю, тут нечего больше оптимизировать...

Спасибо: 0 
ПрофильЦитата Ответить



Пост 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 // << Теперь здесь находятся строки в которых есть ВСЕ ИСКОМЫЕ ФРАЗЫ






Спасибо: 0 
ПрофильЦитата Ответить
Ответ:
1 2 3 4 5 6 7 8 9
большой шрифт малый шрифт надстрочный подстрочный заголовок большой заголовок видео с youtube.com картинка из интернета картинка с компьютера ссылка файл с компьютера русская клавиатура транслитератор  цитата  кавычки моноширинный шрифт моноширинный шрифт горизонтальная линия отступ точка LI бегущая строка оффтопик свернутый текст

показывать это сообщение только модераторам
не делать ссылки активными
Имя, пароль:      зарегистрироваться    
Тему читают:
- участник сейчас на форуме
- участник вне форума
Все даты в формате GMT  3 час. Хитов сегодня: 260
Права: смайлы да, картинки да, шрифты да, голосования нет
аватары да, автозамена ссылок вкл, премодерация откл, правка нет