

jupyter notebook を使ってデータを分析しているのですが、例えばスクレイピングしてきた元データなどは、大きな html
であったりだとか、何かしらの構造を持った文字列である場合が多いです。

であるとすると、複数行ある文字列が2つ与えられたとき、とりあえず(ターミナル的な) diff を取ってみたくなる場合が、個人的に割とあります。

# 質問

jupyter notebook (or, lab) で ipython 上得られた文字列2つがあったとき、ターミナルと同じように line to line
の diff を行い、差分の確認を行いたいと考えているのですが、これを実現する方法は何かありますか?


CC BY-SA 4.0
2022-05-26T10:00:33.407
89067
2022-05-27T10:40:46.963
754
question
jupyter-notebook
jupyter notebook (lab) で文字列の diff を表示したい


差がそれほどないなら, [difflib ---
差分の計算を助ける](https://docs.python.org/ja/3/library/difflib.html) があります。  
(ディレクトリー差分をとるのに
[filecmp.dircmp](https://docs.python.org/ja/3/library/filecmp.html#the-dircmp-
class) と機能比較したことがあり, それほど深くない 2〜3層程度なら十分実用可能)

簡易的なものならこれでも可能かも。  
(コマンドラインの diffと比べれば低機能)

* * *

【例】  
`unified_diff` 使う場合

[code]

    from difflib import unified_diff
    
    # htmla, htmlb の文字列があるとき
    lst1 = htmla.splitlines(keepends=True)
    lst2 = htmlb.splitlines(keepends=True)
    print(''.join(unified_diff(lst1, lst2, fromfile='before.html', tofile='after.html')))
    
[/code]

あるいは色付け

[code]

    lst1, lst2 = map(lambda s: s.strip().split('\n'), (s1,s2))
    out = '\n'.join(unified_diff(lst1, lst2, fromfile='before.py', tofile='after.py', lineterm=''))
    
    from IPython.display import Markdown
    display(Markdown(f'''```diff
    {out}
    ```'''))
    
[/code]

`HtmlDiff` で左右に分けて表示

[code]

    from difflib import HtmlDiff
    from IPython.display import HTML
    
    display(HTML(HtmlDiff().make_file(lst1, lst2)))
    
[/code]

(`HtmlDiff` で生成された比較結果の例)

[code]

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
              "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html>
    
    <head>
        <meta http-equiv="Content-Type"
              content="text/html; charset=utf-8" />
        <title></title>
        <style type="text/css">
            table.diff {font-family:Courier; border:medium;}
            .diff_header {background-color:#e0e0e0}
            td.diff_header {text-align:right}
            .diff_next {background-color:#c0c0c0}
            .diff_add {background-color:#aaffaa}
            .diff_chg {background-color:#ffff77}
            .diff_sub {background-color:#ffaaaa}
        </style>
    </head>
    
    <body>
        
        <table class="diff" id="difflib_chg_to6__top"
               cellspacing="0" cellpadding="0" rules="groups" >
            <colgroup></colgroup> <colgroup></colgroup> <colgroup></colgroup>
            <colgroup></colgroup> <colgroup></colgroup> <colgroup></colgroup>
            
            <tbody>
                <tr><td class="diff_next" id="difflib_chg_to6__0"><a href="#difflib_chg_to6__top">t</a></td><td class="diff_header" id="from6_1">1</td><td nowrap="nowrap"><span class="diff_sub">bacon</span></td><td class="diff_next"><a href="#difflib_chg_to6__top">t</a></td><td class="diff_header" id="to6_1">1</td><td nowrap="nowrap"><span class="diff_add">python</span></td></tr>
                <tr><td class="diff_next"></td><td class="diff_header" id="from6_2">2</td><td nowrap="nowrap">egg<span class="diff_chg">s</span></td><td class="diff_next"></td><td class="diff_header" id="to6_2">2</td><td nowrap="nowrap">egg<span class="diff_chg">y</span></td></tr>
                <tr><td class="diff_next"></td><td class="diff_header" id="from6_3">3</td><td nowrap="nowrap"><span class="diff_sub">ham</span></td><td class="diff_next"></td><td class="diff_header" id="to6_3">3</td><td nowrap="nowrap"><span class="diff_add">hamster</span></td></tr>
                <tr><td class="diff_next"></td><td class="diff_header" id="from6_4">4</td><td nowrap="nowrap">guido</td><td class="diff_next"></td><td class="diff_header" id="to6_4">4</td><td nowrap="nowrap">guido</td></tr>
            </tbody>
        </table>
        <table class="diff" summary="Legends">
            <tr> <th colspan="2"> Legends </th> </tr>
            <tr> <td> <table border="" summary="Colors">
                          <tr><th> Colors </th> </tr>
                          <tr><td class="diff_add">&nbsp;Added&nbsp;</td></tr>
                          <tr><td class="diff_chg">Changed</td> </tr>
                          <tr><td class="diff_sub">Deleted</td> </tr>
                      </table></td>
                 <td> <table border="" summary="Links">
                          <tr><th colspan="2"> Links </th> </tr>
                          <tr><td>(f)irst change</td> </tr>
                          <tr><td>(n)ext change</td> </tr>
                          <tr><td>(t)op</td> </tr>
                      </table></td> </tr>
        </table>
    </body>
    
    </html>
[/code]

* * *

一時ファイルに書き出して構わないなら, コマンドライン版 `diff`も利用可能

[code]

    from pathlib import Path
    html_a = Path('path to file.html')
    html_b = html_a.rename(html_a.with_suffix('.html_bk'))
    with html_a.open('w') as fp:
       pass # 加工
    
    out = !diff -u --suppress-common-lines $html_a $html_b
    
[/code]


CC BY-SA 4.0
2022-05-26T10:59:41.510
89068
2022-05-27T10:40:46.963
2022-05-27T10:40:46.963
43025
43025
89067
answer