Простой скрипт для получения  различий между строк на python, это полезно при создании тестов. Существует стандартная библиотека difflib для этих целей, но я написал для неё более читаемый аналог.

Стандартный вариант

st1 = """/media/user/dd19b13d-bd85-46bb-8db9-5b8f6cf7a825/MyProject/PycharmProject/testfull_pack/venvs/bin/python/scratch_34.py"""
st2 = """/media/user/dd19b13d-bd85-46bb-8et9-5b8f6cf7a825/MyProject/PycharmProjects/testfull_pack/venvs/bin/python/scratch_34.py"""
rs = ''.join(list(difflib.unified_diff(st1, st2)))print(rs)

Ответ:

--- 
+++ 
@@ -30,8 +30,8 @@
 b - 8-d-b+e+t 9 - 5@@ -71,6 +71,7 @@
 e c t+s / t e

Мой скрипт

class colors:
    green = '\x1b[32m'
    reset = '\x1b[0m'
    red = '\x1b[31m'
    black = '\x1b[30m'
    yellow = '\x1b[33m'
    blue = '\x1b[34m'
    magenta = '\x1b[35m'
    cyan = '\x1b[36m'
    white = '\x1b[37m'
    bg_red = '\x1b[41m'
    bg_green = '\x1b[42m'


def diff_string(str1: str, str2: str):
    _max = max([len(str1), len(str2)])

    _len_str1 = len(str1)
    _len_str2 = len(str2)
    _res1 = ''
    _res2 = ''

    for _symbol in range(_max):

        if _symbol < _len_str1 and _symbol < _len_str2:
            if str1[_symbol] == str2[_symbol]:
                _res1 += '{1}{0}{2}'.format(str1[_symbol], colors.green, colors.reset)
                _res2 += '{1}{0}{2}'.format(str2[_symbol], colors.green, colors.reset)
            else:
                _res1 += '{1}{0}{2}'.format(str1[_symbol], colors.red, colors.reset)
                _res2 += '{1}{0}{2}'.format(str2[_symbol], colors.red, colors.reset)
                continue

        elif _symbol < _len_str1:
            _res1 += '{1}{0}{2}'.format(str1[_symbol], colors.bg_green, colors.reset)
            _res2 += '{1}{0}{2}'.format(' ', colors.bg_red, colors.reset)
        elif _symbol < _len_str2:
            _res1 += '{1}{0}{2}'.format(' ', colors.bg_red, colors.reset)
            _res2 += '{1}{0}{2}'.format(str2[_symbol], colors.bg_green, colors.reset)

        else:
            raise ValueError

    return _res1, _res2


if __name__ == '__main__':
    st1 = """/media/user/dd19b13d-bd85-46bb-8db9-5b8f6cf7a825/MyProject/PycharmProject/testfull_pack/venvs/bin/python/scratch_34.py"""
    st2 = """/media/user/dd19b13d-bd85-46bb-8et9-5b8f6cf7a825/MyProject/PycharmProjects/testfull_pack/venvs/bin/python/scratch_34.py"""

    # Пример 1
    rst1, rst2 = diff_string(st1, st2)
    print(f'str1:::\n{rst1}')
    print(f'str2:::\n{rst2}')

Ответ:

Комментарии (7)


  1. petrov_engineer
    26.03.2022 23:43
    +4

    У вас функция неправильно отрабатывает, в строке изменилась подстрока PycharmProject на PycharmProjects, но эта разница подсветилась как-будто изменился весь конец строки.


  1. GCU
    26.03.2022 23:50
    +1

    Почему вы выбрали расстояние Хэмминга вместо Левенштейна для строк?


  1. andreymal
    27.03.2022 00:24
    +2

    Не очень понял, что мешает просто сделать обёртку для difflib с желаемым оформлением:


    def diff_string(str1: str, str2: str):
        rst1 = rst2 = ""
        for op, i1, i2, j1, j2 in difflib.SequenceMatcher(a=str1, b=str2).get_opcodes():
            if op in ("delete", "replace"):
                rst1 += colors.red + str1[i1:i2] + colors.reset
            if op in ("insert", "replace"):
                rst2 += colors.green + str2[j1:j2] + colors.reset
            if op == "equal":
                rst1 += str1[i1:i2]
                rst2 += str2[j1:j2]
        return rst1, rst2

    Но даже если нужно тупое посимвольное сравнение, то вариант из поста можно записать чуть менее громоздко (возможно, можно придумать ещё компактнее, но у меня на ночь глядя мозги не очень варят):


    def diff_string(str1: str, str2: str):
        l1 = len(str1)
        l2 = len(str2)
        rst1 = rst2 = ""
        for a, b in zip(str1, str2):
            color = colors.red if a != b else colors.green
            rst1 += color + a + colors.reset
            rst2 += color + b + colors.reset
        if l1 > l2:
            rst1 += colors.bg_red + str1[l2:] + colors.reset
            rst2 += colors.bg_red + " " * (l1 - l2) + colors.reset
        elif l1 < l2:
            rst1 += colors.bg_red + " " * (l2 - l1) + colors.reset
            rst2 += colors.bg_red + str2[l1:] + colors.reset
        return rst1, rst2


  1. SergeiMinaev
    27.03.2022 04:30

    Можно узнать, зачем у вас все переменные в diff_string() начинаются с подчёркивания?


  1. unsignedchar
    27.03.2022 10:21
    +2

    Выглядит так, будто автор не разобрался, как работает стандартный инструмент, и поэтому запилил свой собственный, аналогов которому нет ;)


  1. gdt
    27.03.2022 13:41

    А я думал динамическое программирование нужно для этого :)


  1. Vishnu
    28.03.2022 09:26

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

    различий между строк

    Это на каком языке?!!