Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Сравнение текстовых полей / 10 сообщений из 10, страница 1 из 1
26.07.2001, 07:35
    #32010393
french
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сравнение текстовых полей
Имела ли место разработка алгоритма сравнения буквенных полей (текстовых) (Ф.И.О. полностью) с реализацией на сервере, большие объемы информации, что-то около Ф.И.О. жителей Московского региона (Москва + М.О.). С решением проблемы Наталья-Наталия, Вячеславовна-Вячеславна и т.д.. Время принятия решения ограничена. Да и вообще, какие на эту тему мысли присутствуют.
...
Рейтинг: 0 / 0
26.07.2001, 08:23
    #32010399
SergSuper
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сравнение текстовых полей
Проще всего имена-отчества(да и фамилии) в явном виде не хранить, а сделать некую таблицу, где каждому имени(отчеству, фамилии) соответсвует некий код, причем для Наталья-Наталия делать его одинаковым. К тому же места в базе будет занимать насравнимо меньше.
...
Рейтинг: 0 / 0
26.07.2001, 08:31
    #32010401
AlexUnik
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сравнение текстовых полей
Могу предложить лишь программу на VBA (встретил когда-то в Инете):

' Функция, осуществляющая оценку сходства двух строк.
' © SBPro Design, С. Брудков, 1999
' Замечания и предложения по адресу:
' sbpro@geocities.com

Option Compare Database
Option Explicit

Public Declare Function GetStringTypeA Lib "kernel32" ( _
ByVal lcid As Long, _
ByVal dwInfoType As Long, _
ByVal lpSrcStr As String, _
ByVal cchSrc As Long, _
lpCharType As Long) As Long

Public Const CT_CTYPE1 = &H1
Public Const CT_CTYPE2 = &H2
Public Const CT_CTYPE3 = &H4

Public Const C1_UPPER = &H1
Public Const C1_LOWER = &H2
Public Const C1_DIGIT = &H4
Public Const C1_SPACE = &H8
Public Const C1_PUNCT = &H10
Public Const C1_CNTRL = &H20
Public Const C1_BLANK = &H40
Public Const C1_XDIGIT = &H80
Public Const C1_ALPHA = &H100

Public Const LOCALE_SYSTEM_DEFAULT = 0

' Вспомогательные функции

Private Function IsSet(Value As Long, Mask As Long) As Boolean
IsSet = (Value And Mask) <> 0
End Function

Private Function IsAlphaNumBlank(S As String) As Boolean
Dim CharType As Long

If Len(S) = 1 Then
GetStringTypeA LOCALE_SYSTEM_DEFAULT, CT_CTYPE1, S, 1, CharType
IsAlphaNumBlank = _
IsSet(CharType, C1_UPPER) Or _
IsSet(CharType, C1_LOWER) Or _
IsSet(CharType, C1_DIGIT) Or _
IsSet(CharType, C1_BLANK)
Else
IsAlphaNumBlank = False
End If
End Function

Private Function CharAt(S As String, N As Long) As String
If (N > 0) And (N <= Len(S)) Then
CharAt = Mid$(S, N, 1)
Else
CharAt = ""
End If
End Function

' Функция сравнивает две строки, подсчитывая общую длину всех совпадающих подстрок.
' Возвращаемое значение нормируется относительно длины строки, т.е. получается
' коэффициент "сходства", который обычно принимает значение от 0 до 1. В некоторых случаях,
' если строка содержит повторяющиеся подстроки, коэффициент может быть больше 1, т.к.
' совпадения этих подстрок учитываются несколько раз (каждая с каждой).
' Параметр Threshold задает минимальную длину подстроки, учитывающуюся при сравнении.
' Для текстов на русском языке рекомендуется значение 5 (подобрано опытным путем при
' сравнении большого количества разнообразных строк), позволяющее не рассматривать большинство
' приставок и суффиксов с окончаниями (напр. пред-, пере-, -ский) как значащие. В то же время
' длина корня слова обычно больше этого порогового значения.

Public Function Similarity(Str1 As String, Str2 As String, Threshold As Long, Optional Debugging As Boolean = False) As Double
Dim tmpStr1 As String
Dim tmpStr2 As String
Dim S As String
Dim StrLen As Long
Dim i As Long
Dim j As Long
Dim TotalLength As Long
Dim PartLength As Long
Dim SeqLength As Long

' предварительное преобразование строк с приведением к одному регистру и удалением
' незначащих (не алфавитно-цифровых) символов.

tmpStr1 = ""
For i = 1 To Len(Str1)
S = CharAt(Str1, i)
If IsAlphaNumBlank(S) Then tmpStr1 = tmpStr1 & LCase(S)
Next i

tmpStr2 = ""
For i = 1 To Len(Str2)
S = CharAt(Str2, i)
If IsAlphaNumBlank(S) Then tmpStr2 = tmpStr2 & LCase(S)
Next i

' Выравнивание длин строк. Более короткая строка заполняется символом '#',
' который в самой строке не встречается и поэтому не влияет на результат.

If Len(tmpStr1) > Len(tmpStr2) Then
tmpStr2 = tmpStr2 & String(Len(tmpStr1) - Len(tmpStr2), "#")
Else
tmpStr1 = tmpStr1 & String(Len(tmpStr2) - Len(tmpStr1), "#")
End If

If tmpStr1 = tmpStr2 Then ' полное совпадение
Similarity = 1
Exit Function
End If

StrLen = Len(tmpStr1)
TotalLength = 0

' Одна строка смещается относительно другой, вычисляется суммарная длина
' совпадающих подстрок, превышающих порог. Суммируются частичные совпадения
' для всевозможных значений смещения.
'
' Для математиков и специалистов по обработке сигналов:
' По сути алгоритм представляет собой вычисление корреляции двух строк
' как их свертки при соответствующим образом подобранной мере на
' пространстве строк. Выбранная мера определяет интеграл, используемый
' при вычислении свертки.

For j = -(StrLen - 1) To StrLen - 1
PartLength = 0
SeqLength = 0

For i = 1 To StrLen
If CharAt(tmpStr1, i) = CharAt(tmpStr2, i + j) Then
SeqLength = SeqLength + 1
Else
If SeqLength > Threshold Then
PartLength = PartLength + SeqLength
End If
SeqLength = 0
End If
Next i

If SeqLength > Threshold Then PartLength = PartLength + SeqLength

' В отладочное окно выводятся результаты сравнения сдвинутых относительно
' друг друга строк. Совпадающие подстроки отмечены.

If Debugging Then
If PartLength > Threshold Then
Debug.Print j; PartLength
If j > 0 Then
Debug.Print String(j, " "); tmpStr1
Debug.Print String(j, " ");
For i = 1 To StrLen
If CharAt(tmpStr1, i) = CharAt(tmpStr2, i + j) Then
Debug.Print "|";
Else
Debug.Print " ";
End If
Next i
Debug.Print
Debug.Print tmpStr2
Debug.Print "==========================="
End If

If j < 0 Then
Debug.Print tmpStr1
For i = 1 To StrLen
If CharAt(tmpStr1, i) = CharAt(tmpStr2, i + j) Then
Debug.Print "|";
Else
Debug.Print " ";
End If
Next i
Debug.Print
Debug.Print String(-j, " "); tmpStr2
Debug.Print "==========================="
End If

If j = 0 Then
Debug.Print tmpStr1
For i = 1 To StrLen
If CharAt(tmpStr1, i) = CharAt(tmpStr2, i + j) Then
Debug.Print "|";
Else
Debug.Print " ";
End If
Next i
Debug.Print
Debug.Print tmpStr2
Debug.Print "==========================="
End If
End If
End If

TotalLength = TotalLength + PartLength
Next j

If Debugging Then
Debug.Print tmpStr1
Debug.Print tmpStr2
Debug.Print TotalLength, StrLen, TotalLength / StrLen
Debug.Print "------------------------"
End If

Similarity = TotalLength / StrLen
End Function
...
Рейтинг: 0 / 0
26.07.2001, 09:40
    #32010409
GreenSunrise
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сравнение текстовых полей
А зачем сюда VB пихать ? Чтобы тормозов побольше было ? Такие вещи надо делать в рамках сиквела...
...
Рейтинг: 0 / 0
26.07.2001, 11:08
    #32010419
SergSuper
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сравнение текстовых полей
Врядли понадобиться, но я решил переписать предложенную AlexUnik функцию на SQL. Получилось чуть короче, но работать будет скорее всего медленно.
Наверное потому что я не "математик и не специалист по обработке сигналов" и не знаю "алгоритма вычисление корреляции двух строк как их свертки при соответствующим образом подобранной мере на пространстве строк"

Функция выдаёт максимальную длинну совпадающих подстрок.
3-й параметр - максимальная длинна сравниваемых подстрок.

Так же необходима таблица
CREATE TABLE Millenium (
num int NULL
)
в которой вставлены числа от 1 до максимальной длинны строк(можно больше).

CREATE FUNCTION compare
(@word1 varchar(100),
@word2 varchar(100),
@charcount int)
RETURNS int
AS
BEGIN
declare @i1 int,@i2 int, @res int
declare @w1 varchar(100), @w2 varchar(100)

select @w1=upper(@word1),@w2=upper(@word2), @res=0
select @i1=datalength(@w1), @i2=datalength(@w2)

select @res=max(sz.num)
from Millenium s1, Millenium s2, Millenium sz
where sz.num<=@charcount and s1.num<=@i1-sz.num+1 and s2.num<=@i2-sz.num+1
and substring(@w1,s1.num,sz.num)=substring(@w2,s2.num,sz.num)
and sz.num>0 and s2.num>0 and s2.num>0

return @res
END

go

select dbo.compare('11113331111','2222223321',9)
...
Рейтинг: 0 / 0
26.07.2001, 11:28
    #32010422
pkarklin
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сравнение текстовых полей
А как на счет полнотекстовых индексов, и соответсвующих функций CONTAINS, CONTAINSTABLE... в связке с ситемой поддержки полнотестовых индексов на Русском языке, например, Следопыт для SQL 2000 от MediaLingva. Кто нибудь это пробовал?
...
Рейтинг: 0 / 0
26.07.2001, 13:23
    #32010438
AlexUnik
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сравнение текстовых полей
2 SergSuper
Класс! Если это работает, можно воспользоваться?
...
Рейтинг: 0 / 0
26.07.2001, 14:32
    #32010446
SergSuper
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сравнение текстовых полей
2 AlexUnik

Вообще я если пишу то, что не проверил, то обычно как-нибудь это оговариваю(хотя в любом случае гарантию что нет ошибок дать не могу).

А работает на удивление быстро, я запустил сравнение двух таблиц, перебор 22000 записей занял около 2 мин., я ожидал раз в 10 медленнее.

Пользоваться конечно можно, а вообще я это писал так, to challenge. Раздражает меня когда что-то написано слишком длинно. И главное так красиво назвал "вычисление корреляции двух строк...", а по сути стоит тупой перебор в цикле. На процедурном языке такие задачи решаются не так.
...
Рейтинг: 0 / 0
27.07.2001, 05:01
    #32010471
AlexUnik
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сравнение текстовых полей
2 SergSuper
Как видно из комментария в моем примере, этот код написан не мной. Переписать его под что-то путное не возникало необходимости. Причина того, что я его выложил здесь - фраза "Да и вообще, какие на эту тему мысли присутствуют."
Ваш стиль написания кода мне очень по душе. Только сам я пока слишком далек от такого профессионализма. Но ничего, какие мои годы
...
Рейтинг: 0 / 0
01.08.2001, 12:31
    #32010875
French
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сравнение текстовых полей
Огромное спасибо всем кто написал свои соображения и спеиальное AlexUnik и SergSuper. Вы все мне очень помогли. С уважением Алексей
...
Рейтинг: 0 / 0
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Сравнение текстовых полей / 10 сообщений из 10, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]