Форум сайта python.su
Мне нужно будет сравнить и сопоставить несколько тысяч наименований, которые могут быть написаны с небольшими различиями. Гарантия распознавания не требуется, это нужно для первичной фильтрации, чтобы сократить сравниваемые коллекции, потом уже будут использоваться более сложные сравнения по нескольким критериям.
(если конкретнее, то мне нужно упорядочить медиатеку и речь идет о тэгах mp3-файлов)
Про дистанцию Левенштайна и различные модули fuzzy-match я знаю, но они для этой задачи не слишком удобны; они дают оценку похожести строк, но тогда придется где-то запоминать исходные строки и их похожесть.
Вообще в идеале мне нужно что-то вроде хэш-функции, которая бы игнорировала все несущественные части строки и возвращала хэш, который был бы одинаковым для идентичных (но различающихся в мелочах) строк.
В примитивном виде что-то вроде такого:
def simplify(title: str) -> str: str = str.casefold() str = re.sub(r'[^\w]'gm, '', str) return title
Офлайн
alibekТы составь сначала множество входных данных. Потом составь множество преобразований входных данных в выходные данные. Наполни это всё максимально. И когда оно у тебя будет всё, тогда и станет понятно, как их приводить к упрощённому единому виду.
Мне нужно будет сравнить и сопоставить несколько тысяч наименований, которые могут быть написаны с небольшими различиями. Гарантия распознавания не требуется, это нужно для первичной фильтрации, чтобы сократить сравниваемые коллекции, потом уже будут использоваться более сложные сравнения по нескольким критериям.
(если конкретнее, то мне нужно упорядочить медиатеку и речь идет о тэгах mp3-файлов)
Отредактировано py.user.next (Авг. 17, 2023 22:52:49)
Офлайн
Немного усложнил функцию:
def simplify(str: str) -> str: str = str.casefold() str = unidecode(str) str = re.sub(r'[^\w\s]', '', str) str = re.sub(r'[\s ]+', ' ', str) str = str.strip() return str
Офлайн
alibekХорошо хоть, что не говоришь, что это правильно.
В общем, для моих практических целей функции достаточно.
alibekКороче, ты видишь вот всё зелёненьким таким раскрасилось? или ты дальтоник?def simplify(str: str) -> str: str = str.casefold() str = unidecode(str) str = re.sub(r'[^\w\s]', '', str) str = re.sub(r'[\s ]+', ' ', str) str = str.strip() return str
>>> str.upper('abc') 'ABC' >>> >>> 'abc'.upper() 'ABC' >>>
>>> lst = [1, 2, 3, 4, 5] >>> >>> out = list(map(str, lst)) >>> out ['1', '2', '3', '4', '5'] >>>
>>> lst = ['abc', 'DeF', 'gHi'] >>> >>> out = list(map(str.upper, lst)) >>> out ['ABC', 'DEF', 'GHI'] >>>
str = ... str = ... str = ... str = ...
string0 = string string1 = ... string0 ... string2 = ... string1 ... string3 = ... string2 ... string4 = ... string3 ... out = string4
report = {'ok': {string1, string2, string3, string4, 'fail': {string9, string10}} print(report)
alibekЭто делается вот так, потому что пробел и так уже находится внутри \s (класс пробельных символов)str = re.sub(r'[\s ]+', ' ', str)
string = re.sub(r'\s+', ' ')
>>> import re >>> >>> re.sub(r'.+', 'x', 'abc\ndef\nghi') 'x\nx\nx' >>> >>> re.sub(r'.+', 'x', 'abc\ndef\nghi', flags=re.S) 'x' >>>
Отредактировано py.user.next (Авг. 19, 2023 00:49:34)
Офлайн
alibekПриведи примеры какие данные у тебя на входе, и что ждешь на выходе
Мне нужно будет сравнить и сопоставить несколько тысяч наименований, которые могут быть написаны с небольшими различиями.
Офлайн
Например.
Abba, ABBA -> abba
Bomfunk MC s, Bomfunk MC's, Bomfunk MC-s, Bomfunk MCs -> bomfunk mcs
Chimène Badi, Chimene Badi -> сhimene badi
E-Type, E Type -> e type
Mylène Farmer, Mylene Farmer -> mylene farmer
L.E.J., LEJ, L E J, L_E_J - > l e j
The Offspring, Offspring -> offspring
А'Студио, А-студио, А Студио -> a studio
Ёлка, Елка -> elka
Это упрощение по имени исполнителя, тут чуть проще. Хотя и тут есть нюансы (например несколько исполнителей, или исполнители типа “Nick Cave and The Bad Seeds”, где вторая часть может отсутствовать, писаться через &, запятую, тире, без артикля).
Еще будет упрощение по названию альбома и названию трека.
Тут ожидаются свои сложности, особенно с названиями альбомов.
Понятно, что однозначной идентификации не будет, потому что вариантов написания может быть слишком много и не все из них можно распознать.
Но хотя бы основное, потому что это первичная фильтрация, просто чтобы сократить объем работы скрипту для более тщательного сравнения.
А уж коллизии или неправильное разделение я обработаю вручную, если процент таких неправильных срабатываний будет небольшим.
Всего же у меня где-то порядка 150 ГБ музыки и порядка 30 тысяч треков.
Конечно там будут дубли или некачественные треки, поэтому после обработки коллекция сократится где-то на четверть или на треть.
Но все равно слишком много для ручной обработки.
Отредактировано alibek (Авг. 21, 2023 00:08:54)
Офлайн
На домашнем ПК добавил в adblock-фильтр строку:
python.su#?#div.blockpost:-abp-has(div.postleft strong:-abp-contains(py.user.next))
py.user.nextСтрого говоря нет.
Ну, например, вот здесь
py.user.nextНельзя — это когда syntax error. Все остальное можно.
Поэтому его нельзя перекрывать
py.user.nextЯ как бы это знаю.
в твоём случае каждое имя теряется после его обработки
py.user.nextНе существенно. Уверен даже, что внутренний оптимизатор регулярных выражений умеет сам убирать подобные дубли.
пробел и так уже находится внутри \s
py.user.nextПлюс бывает жадный и нежадный.
плюс бывает длинный и короткий
py.user.nextНужная задача описана в первых двух абзацах и кода там нет.
Не надо задание формулировать в виде кода и тем более не надо его другим объяснять на коде.
py.user.nextДа? А как же 13 принцип дзена Питона?
И ты приходишь туда по этой ссылке, и там 100500 решений этой задачи со всех сторон.
Отредактировано alibek (Авг. 21, 2023 09:50:25)
Офлайн
py.user.nextХотя, нет.
потому что пробел и так уже находится внутри \s
Офлайн
alibekНу у тебя пробелы везде записаны там
Хотя, нет.
Это не пробел.
Это символ U+00A0 и он не находится внутри \s.
>>> r"str = re.sub(r'[\s ]+', ' ', str)" "str = re.sub(r'[\\s ]+', ' ', str)" >>> list(map(ord, r"str = re.sub(r'[\s ]+', ' ', str)")) [115, 116, 114, 32, 61, 32, 114, 101, 46, 115, 117, 98, 40, 114, 39, 91, 92, 115, 32, 93, 43, 39, 44, 32, 39, 32, 39, 44, 32, 115, 116, 114, 41] >>>
alibek
Во-вторых str это не класс, а тип.
>>> str <class 'str'> >>>
>>> type(type) <class 'type'> >>> >>> type(str) <class 'type'> >>> >>> type('') <class 'str'> >>> >>> type(lambda: 1) <class 'function'> >>> >>> issubclass(type(lambda: 1), type) False >>> issubclass(type(str), type) True >>> >>> issubclass('', type) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: issubclass() arg 1 must be a class >>> >>> issubclass(str, type) False >>>
alibekЯ бы на твоём месте вообще с этой штукой не копался, так как слишком уж он хреново написан. Но больше ничего нет, поэтому приходится юзать это говно в качестве единственной вещи, занявшей нишу в своё время. Открой просто его код и посмотри. Так что твои настройки запросто могут слететь сами собой при каком-нибудь обновлении. Ты их там мучился, писал, а они раз и слетели, потому что процедура обновления этого расширения не отлажена нормально.
На домашнем ПК добавил в adblock-фильтр строку:
alibekНу форум раскрасил потому, что никто не будет это использовать в качестве имени переменной или функции, так как все знают, что встроенные имена перекрывать нельзя. Они могут понадобится потом, а они перекрыты. Ну тупень какой-нибудь, конечно же, будет делать del, чтобы использовать в своём коде перекрытое им же самим встроенное имя. А умный человек всё-таки выучит все имена (благо они указаны все на одной страничке) и не будет позориться так уж, как новичок уровня школоты.
То есть то, что форум “раскрасил зелененьким” это не класс str, а одноименная переменная str
alibekТам вообще больше понятий всяких: жадный, ленивый, ревнивый. И это всё разные вещи. Поэтому лучше их не использовать, а прямо так и разделить на два вида: длинный и короткий. Если ты ревнивый жадным назовёшь, то ты ошибёшься. Если же я ревнивый назову длинным или жадный назову длинным, то я не ошибусь в обоих случаях.
Плюс бывает жадный и нежадный.
alibekЭто не токен, а метасимвол. Метасимвол - символ, описывающий какой-то символ.
А то, что вы описали — это называется флаг ‘single line’ (или ‘multi line’), и влияет на поведение токена “.”
alibekУбирает - не убирает, это неважно. Сам код должен быть чистый, а не замусоренный. Почитай нормальные коды каких-нибудь программ. И почитай замусоренные коды каких-нибудь программ. Сразу поймёшь, в чём разница. Пример - этот adblock, к которому даже прикасаться не хочется, настолько там всё наговнокожено. Жалко время тратить на него, чтобы разобраться сначала, что там ценного, а что там просто так. Другое дело какие-нибудь исходники Git'а, которые вычищены до блеска японцем. Так там и читать приятно, и сделать что-нибудь хочется, подредактировать что-то в программе.
Уверен даже, что внутренний оптимизатор регулярных выражений умеет сам убирать подобные дубли.
alibekНу, например, ты удаляешь какое-то из этих преобразований, потому что оно оказалось ненужным, и тут раз и ты пропускаешь момент, что оно вообще-то привязано к предыдущему преобразованию, а следующее преобразование привязано к нему. И потом наступает момент (после нескольких таких удалений и добавления новых преобразований), что ты смотришь в имя string в какой-то строке кода и просто не знаешь, что в нём находится. В то же время фиксированные разные имена в любой момент сообщают о том, кто они и что в них хранится.
Я как бы это знаю.
А зачем мне хранить промежуточные значения?
alibekНе посмотришь ты ничего. Этот код будет на хостинге стоять где-нибудь и пользоваться им будут сто бухгалтерш тупых одновременно. Попробуй тормозни его, они разорутся там все. Они тебе просто скажут “у нас такая-то ошибка выскакивает” и ты прямо на сервере должен будешь смотреть свою программу. Какой дебаггер? На это нет времени, да и дебаггер сам может не поставиться туда.
Если вдруг функция будет работать не так, как ожидается, я ее прослежу в режиме отладки и просмотрю промежуточные значения уже непосредственно, на каждом шаге.
alibekДа вообще-то нет. Элемент report делается в исключении. А исключение если выходит, то после выхода из функции распространяется дальше по программе. Его никак не пропустишь, если, конечно, не будешь тупить и перехватывать все исключения и гасить их все по умолчанию. Так что оно может быть и в середине, и в конце. И вот что оно будет выводить? Какое-то пятидесятое преобразование из ста преобразований, потому что предыдущие сорок стали неизвестными? Ты сэкономил имена, якобы какие-то ресурсы, но в итоге ты не сэкономил, а превратил всё в два притопа три прихлопа, с которыми потом ничего не сделаешь, пока не превратишь их в нормальные имена, где все имена разделены.
А еще лучше — добавить отладочный вывод значения после каждой строки. Это будет правильнее, чем делать вывод report общим списком — если при выполнении функции будет что-то не то, то код до вывода report может и не дойти, а отладочный вывод максимально точно укажет место сбоя.
alibekИмена в питоне ничего не расходуют.
Не говоря уж о том, что это лишний расход ресурсов.
alibekНельзя надевать сапог на голову. Надеюсь, ты не в сапоге сидишь. Нельзя прыгать с девятиэтажки. Нельзя махать руками, как крыльями, пытаясь улететь с крыши дома. Ну ты можешь так делать, но это плохо закончится. Поэтому никто так не делает. В питоне всё то же самое, есть свои сапоги и девятиэтажки. Один ты вот в сапоге на голове поднялся на крышу уже и ищешь её край, чтобы полететь, как птица, размахивая руками-крыльями. Другие же просто крутят пальцами у виска.
Нельзя — это когда syntax error. Все остальное можно.
alibekНе, по одному словесному описанию задачи должно быть понятно всё без дополнительных уточнений и вопросов. Но так как изначально непонятно в этом словесном описании ничего конкретного, xam1816'у пришлось у тебя переспросить про данные, чтобы уточнить задачу. Так вот ты должен был это всё написать сразу и без единой строчки кода. Тогда тебе бы вывалили код сразу, ну или решение тоже на словах (я обычно так делаю, потому что, во-первых, люди учатся сами и я сорву им обучение, если выдам готовый код, а во-вторых, это удобно по времени и по буквам, мне не надо много и долго писать).
Нужная задача описана в первых двух абзацах и кода там нет.
Код приведен в качестве пояснения (примера), уже после самой задачи.
alibekДзен питона соблюдается, принципы UNIX соблюдаются, принципы SOLID соблюдаются и многие другие принципы соблюдаются. А про 100500 решений я имел в виду то, что бывает кривое решение, содержащее один единственный полезный элемент, который можно взять на заметку. Потом из другого решения можно взять другой элемент полезный. Потом из третьего решения можно взять третий элемент полезный. Потом эти все элементы взятые или там идеи объединяются и делается своё оптимальное решение.
Да? А как же 13 принцип дзена Питона?
Впрочем, я с ним категорически не согласен и считаю правильным основной девиз Perl.
Отредактировано py.user.next (Авг. 22, 2023 03:21:30)
Офлайн
py.user.nextДа, при отправке в форум символ заменился на обычный пробел.
Ну у тебя пробелы везде записаны там
py.user.nextКак минимум они занимают место в каком-нибудь внутреннем указателе или словаре для области видимости функции, уж не знаю, как в питоне это реализовано.
Имена в питоне ничего не расходуют.
Офлайн