Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 04.09.2017, 14:59   #1
PTyTb32
Форумчанин
 
Регистрация: 06.10.2013
Сообщений: 216
По умолчанию Выбор максимально похожей строки

Привет, есть список с названиями участков:
ДЭУ №1
ДЭУ №3(41)
ПК ЮГ
АБЗ МКАД Запад
ПК Запад
и т.д.

и есть список файлов с сотрудниками:
новые дэу1
сотрудники пк юг новые
список новых сотрудников дэу3-41
и т.д.

задача: по имени файла узнать какой это участок (из списка)

проблема в том, что многие называют участок не так как в базе, к примеру где то есть пробел, где то нет, где то есть скобки, где то нет.

пробовал: искать нужные участки с помощью функции POS, с помощью той же функции и Delete удалял явно лишние слова, но все равно не получается сделать это автоматически(((

Подскажите пожалуйста в какую сторону копать? как найти наиболее подходящий из списка?
PTyTb32 вне форума Ответить с цитированием
Старый 04.09.2017, 15:58   #2
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,229
По умолчанию

Цитата:
Сообщение от PTyTb32 Посмотреть сообщение
проблема в том, что многие называют участок не так как в базе, к примеру где то есть пробел, где то нет, где то есть скобки, где то нет.
скорее всего не получится решить чисто административную задачу программным способом.
нужно либо составлять словарь перекодирования (вручную - слово - как они называют и соответствующее ему значение - как это называется правильно).
Либо административным путём решать - все обязать называть правильно.
для этого разослать инструкцию со списком правильных названий. Кто не следует инструкции - наказывать. Постепенно всё будет правильно.


Цитата:
Сообщение от PTyTb32 Посмотреть сообщение
Подскажите пожалуйста в какую сторону копать? как найти наиболее подходящий из списка?
а что, если автоматически найдётся похожий, но НЕПРАВИЛЬНЫЙ, Вас это устроит?


p.s. вообще. формально говоря, нужно выбрасывать из строки все незначимые символы (в начале и конце строки вообще удалять, в середине все подряд идущие символы (пробелы, тире, скобки и т.п.) заменять на один символ. например, ДЭУ №1
ДЭУ №3(41)
ПК ЮГ
АБЗ МКАД Запад
ПК Запад_", оставшиеся символы строки приводить к одном регистру (либо строчные, либо ПРОПИСНЫЕ буквы). потом сравнивать.
т.е. будет
ДЭУ_1
ДЭУ_3_41
ПК_ЮГ
АБЗ_МКАД_ЗАПАД
ПК_ЗАПАД

и тоже самое делать со списком файлов.
НО! Есть ненулевая вероятность получить неверное значение (коллизию) или, более вероятно, вообще не получить совпадения (ведь можно написать и ДЕЭ №1 и Д Э У - Один, "1-е ДЭУ" и "ДЭУ номер 1" и "ДЭУ1" и т.д. и т.п.
Serge_Bliznykov вне форума Ответить с цитированием
Старый 04.09.2017, 16:10   #3
PTyTb32
Форумчанин
 
Регистрация: 06.10.2013
Сообщений: 216
По умолчанию

Цитата:
Сообщение от Serge_Bliznykov Посмотреть сообщение
ведь можно написать и ДЕЭ №1 и Д Э У - Один, "1-е ДЭУ" и "ДЭУ номер 1" и "ДЭУ1" и т.д. и т.п.
вот они так и делают, я хотел программно разделить это что бы лишний раз не напрягать людей, но видимо не получится... слишком много гребаных условий
PTyTb32 вне форума Ответить с цитированием
Старый 04.09.2017, 19:04   #4
Filka
Форумчанин
 
Регистрация: 29.10.2015
Сообщений: 273
По умолчанию

Код:
const
  cNames: array[0..4] of string = ('ДЭУ №1', 'ДЭУ №3(41)', 'ПК ЮГ',
    'АБЗ МКАД Запад', 'ПК Запад');

procedure TForm1.Button1Click(Sender: TObject);
var
  I, N1, N2, R: Integer;
begin
  R := -1;
  N1 := 0;
  N2 := 0;
  for I := Low(cNames) to High(cNames) do
  begin
    // Функция IndistinctMatching взята отсюда
    // http://delphikingdom.com/asp/viewitem.asp?catalogid=722
    N1 := IndistinctMatching(4, Edit1.Text, cNames[I]);
    if N1 > N2 then
    begin
      N2 := N1;
      R := I;
    end;
  end;
  if R <> -1 then
    ShowMessage(cNames[R]);
end;
?
Filka вне форума Ответить с цитированием
Старый 04.09.2017, 19:05   #5
Sciv
Старожил
 
Аватар для Sciv
 
Регистрация: 16.05.2012
Сообщений: 3,211
По умолчанию

Цитата:
Сообщение от PTyTb32 Посмотреть сообщение
что бы лишний раз не напрягать людей, но видимо не получится... слишком много гребаных условий
Можно разделить программно то, что определяется, и то, что не определяется. Первую часть, соответственно, обработать автоматически, а вторую - отдать людЯм на растерзание. Всё же полегче будет...
Начал решать проблему с помощью регулярных выражений. Теперь решаю две проблемы...
Sciv вне форума Ответить с цитированием
Старый 04.09.2017, 19:17   #6
Slym
Участник клуба
 
Регистрация: 07.12.2011
Сообщений: 1,025
По умолчанию

Нечёткий поиск
читаем https://habrahabr.ru/post/336906/
выдираем алгоритмы
портируем код
Не стесняемся, плюсуем!
Slym вне форума Ответить с цитированием
Старый 05.09.2017, 08:20   #7
min@y™
Цифровой кот
Старожил
 
Аватар для min@y™
 
Регистрация: 29.08.2014
Сообщений: 7,629
По умолчанию

Код:
function StringSimilarity(const AOrigin, ABuffer: string): Single;
var
  Index, oLen, bLen, Count: Integer;
  oSymb, bSymb: Word;
  Sum: Single;
begin
{ кол-во символов, которые не совпадают, всегда меньше кол-ва несовпадений.
  aaaa <---> aaaa : 0 + 0 + 0 + 0 = 0     (1/1 + 1/1 + 1/1 + 1/1)/4 = 1.00
  aaaa <---> aaab : 0 + 0 + 0 + 1 = 1     (1/1 + 1/1 + 1/1 + 1/2)/4 = (7/2)/4 = 0.875
  aaaa <---> aaac : 0 + 0 + 0 + 2 = 2
  ......
  aaaa <---> aaaa : 0 + 0 + 0 + 0 = 0
  aaaa <---> aaba : 0 + 0 + 1 + 0 = 1
  aaaa <---> aabb : 0 + 0 + 1 + 1 = 2
  ......
  aaaa <---> bcde : 1 + 2 + 3 + 4 = 10     (1/2 + 1/3 + 1/4 + 1/5)/4 = 0.32083333333333333333333333333333}
  
  Result:= 1.0;
  oLen:= Length(AOrigin);
  bLen:= Length(ABuffer);

  Count:= Max(oLen, bLen);
  if Count = 0
    then Exit;

  Sum:= 0.0;

  for Index:= 1 to Count do
    begin
      if Index <= oLen
        then oSymb:= Word(AOrigin[Index])
        else oSymb:= 0;

      if Index <= bLen
        then bSymb:= Word(ABuffer[Index])
        else bSymb:= 0;

      Sum:= Sum + 1.0 / (1 + Abs(oSymb - bSymb));
    end;

  Result:= Sum / Count;
end;

procedure CalcAverSimilarities(ALines: TStrings);
var
  oIndex, bIndex, Count: Integer;
  Coef: Single;
begin
  Count:= ALines.Count;

  for oIndex:= 0 to Count - 1 do
    begin
      Coef:= 0.0;

      for bIndex:= 0 to Count - 1 do
        Coef:= Coef + StringSimilarity(ALines[oIndex], ALines[bIndex]);

      Coef:= Coef / Count;
      ALines.Objects[oIndex]:= Pointer(Coef);
    end;
end;
Расскажу я вам, дружочки, как выращивать грибочки: нужно в поле утром рано сдвинуть два куска урана...
min@y™ вне форума Ответить с цитированием
Старый 06.09.2017, 09:44   #8
PTyTb32
Форумчанин
 
Регистрация: 06.10.2013
Сообщений: 216
По умолчанию

Цитата:
Сообщение от Sciv Посмотреть сообщение
Можно разделить программно то, что определяется, и то, что не определяется. Первую часть, соответственно, обработать автоматически, а вторую - отдать людЯм на растерзание. Всё же полегче будет...
да я так и сделал пока, пользователь тыкает на очередного сотрудника и выбирает какому у частку он соответствует, дальше программа заменяет подразделение у всех сотрудников из этого файла, но тут есть еще один ответ который смотрит на релевантность сравнения, попробую с ней околдовать)) Спасибо Filka
и да!!!! оно работает!!! еще много спасибо Filka!!!!!

Последний раз редактировалось PTyTb32; 06.09.2017 в 10:01.
PTyTb32 вне форума Ответить с цитированием
Старый 06.09.2017, 10:31   #9
Filka
Форумчанин
 
Регистрация: 29.10.2015
Сообщений: 273
По умолчанию

Пожалуйста.
Filka вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
В каждой строке вибираеться минимальное число, а затем среди этих чисел вибираеться максимально. Вивести на экран номер строки в котором находится это число. Анастасия3006 Помощь студентам 1 26.12.2016 01:20
А если заменить имеющиеся транзисторы на матери на более мощные (С похожей ВАХ), будет выигрыш? Антоним Компьютерное железо 0 30.09.2016 14:03
Выбор минимального значения в максимально возможных. Вадим_$ Microsoft Office Excel 6 14.05.2011 00:34
выбор текста из строки maksim_serg Microsoft Office Excel 2 15.04.2010 14:15
Выбор инициалов из строки Swatch Microsoft Office Access 6 05.03.2010 13:53