python CSV出力（に使用するデータの読み込み）について Part2


先日質問させていただきましたCSV出力について（[前回の質問リンク先](https://ja.stackoverflow.com/questions/80728/python-
csv%E5%87%BA%E5%8A%9B-%E3%81%AB%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BF-%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)）では、理解しないまま、取り合えず動く状態にしたという状態のため、理解が伴っておりませんでした。

これでは、上達しないと思い、テキスト処理やループ、リスト等をしっかりと理解し  
少しでも上達したいと思い、再度、質問させていただきます。  
（先日の皆様の回答、アドバイスは、私には高度すぎました。。。）

そこで、下記条件①②までは、自分なりになんとか処理できましたが、  
その結果を、どの様にCSV形式にしていけばよいかが分かりません。  
一旦、辞書形式にする方が良いのか、辞書形式にする場合、ループ処理を使うのか、  
それとも、：で分割してみるのが良いのか・・・等々、ここから、どの様に  
CSV形式にすればよいか、分からない状態です。  
つきましては、再度、アドバイスを頂ければと思います。

条件  
①システムに 1 インターフェイスがあります: を削除  
② ホストされたネットワークの状態: 利用不可 を削除  
③名前からプロファイル名までをCSV形式へ変換し、sample.csvとして保存

[code]

    システムに 1 インターフェイスがあります:
    
        名前                   : Wi-Fi
        説明                   : Qualcomm Atheros QCA61x4A Wireless Network Adapter
        GUID                   : 000000000000000000
        物理アドレス           : xx:xx:xx:xx:xx:xx
        状態                   : 接続されました
        BSSID                  : xx:xx:xx:xx:xx:xx
        ネットワークの種類     : インフラストラクチャ
        無線の種類             : 802.11n
        認証                   : WPA2-パーソナル
        暗号                   : CCMP
        接続モード             : 自動接続
        チャネル               : 6
        受信速度 (Mbps)        : 144.4
        送信速度 (Mbps)        : 144.4
        シグナル               : 94%
        プロファイル           : sample-wifi
    
        ホストされたネットワークの状態: 利用不可
    
[/code]

[code]

    # readlines()でリスト形式で読み込む
    
    with open('example.txt', encoding='utf-8') as f:
        contents = f.readlines()
    
    # ①システムに 1 インターフェイスがあります:
    # ② ホストされたネットワークの状態: 利用不可
    # を削除するため、上記①②が何番目のリストになるか確認
    
    count = 0
    for line in contents:
        print(f"{count} -> {line.strip()}")
        count += 1
    
    # ①②は、0番目と19番目になるため、それ以外を
    # 表示（取り出すため） for new_line in contents[2:18]とする。
    
    for new_line in contents[2:18]:
        print(new_line.strip())
    
[/code]




> # ①システムに 1 インターフェイスがあります:  
>  # ② ホストされたネットワークの状態: 利用不可  
>  # を削除するため、上記①②が何番目のリストになるか確認

Python の場合、リストのインデックスに負の整数値を指定することができます。意味としてはリストの末尾から先頭へ向かっての順番になります。

[code]

    >>> lst = [1, 2, 3, 4, 5, 6]
    >>> lst[-1]   # 末尾の要素
    6
    >>> lst[-2]   # 末尾から先頭へ向かって 2 番目の要素
    5
    >>> lst[2:-2] # 「先頭から 3 番目の要素」から「末尾から先頭へ向かって 3 番目の要素」まで
    [3, 4]
    
[/code]

つまり、以下の様に書いても同じ結果になります。

[code]

    with open('example.txt', encoding='utf-8') as f:
        contents = f.readlines()
    
    for new_line in contents[2:-2]:
        print(new_line.strip())
    
[/code]

もっとも、`netsh wlan show interface` コマンドの出力形式を考慮すれば「空行(blank
line)」で区切られた領域を抽出する」ことになるので以下の様にも書けます。この場合、`contents`
の中身はリストではなく改行コードを含む文字列になります。

[code]

    import re
    
    with open('example.txt', encoding='utf-8') as f:
      contents = f.read()
    
    contents = re.split(r'\r?\n\r?\n', contents)[1]
    
[/code]

**ConfigParser**

> その結果を、どの様にCSV形式にしていけばよいかが分かりません。

`netsh` コマンドの出力は基本的に Windows の INI ファイルと同様の構造で構成されています。違いは INI ファイルではパラメータを
`name=value` 形式で表記しますが、`netsh` では `property : value` になります。また、INI
ファイルにはセクション(`[group_name]`)がありますが、`netsh`
にはありません。その他にも違いはありますが、今回の場合は影響しませんので言及しません。

Python では、この INI ファイルと同様の構造を持つファイルをパース(解析)するためのモジュールが提供されています。

[configparser ---
設定ファイルのパーサー](https://docs.python.org/ja/3/library/configparser.html#module-
configparser)

> このモジュールは、 Microsoft Windows の INI ファイルに似た構造を持ったベーシックな設定用言語を実装した ConfigParser
> クラスを提供します。このクラスを使ってユーザーが簡単にカスタマイズできる Python プログラムを作ることができます

今回の場合の実装例を以下に示します。

[code]

    import configparser
    import csv
    import re
    
    with open('example.txt', encoding='utf-8') as f:
        contents = f.read()
    
    # 「名前」から「プロファイル」までを抽出
    contents = re.split(r'\r?\n\r?\n', contents)[1]
    
    dummy = 'dummy'
    # デリミタを :(コロン)に設定
    parser = configparser.RawConfigParser(delimiters=(':'))
    # contents には INI ファイルの様な「セクション」がないので
    # ダミーセクションを付加
    parser.read_string(f'[{dummy}]\n' + contents)
    # 行と列を入れ替える(transpose)
    table = [*zip(*(parser[dummy].items()))]
    
    # CSV 形式で保存
    with open('sample.csv', 'w', encoding='utf-8') as c:
      cw = csv.writer(c, quoting=csv.QUOTE_MINIMAL)
      cw.writerows(table)
    
[/code]

**sample.csv**

名前 | 説明 | guid | 物理アドレス | 状態 | bssid | ネットワークの種類 | 無線の種類 | 認証 | 暗号 | 接続モード |
チャネル | 受信速度 (mbps) | 送信速度 (mbps) | シグナル | プロファイル  
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---  
Wi-Fi | Qualcomm Atheros QCA61x4A Wireless Network Adapter | 0 |
xx:xx:xx:xx:xx:xx | 接続されました | xx:xx:xx:xx:xx:xx | インフラストラクチャ | 802.11n |
WPA2-パーソナル | CCMP | 自動接続 | 6 | 144.4 | 144.4 | 94% | sample-wifi

