LoginSignup
1
1

More than 5 years have passed since last update.

pythonでpython (とR) スクリプト内の不要なコメントを消す

Last updated at Posted at 2017-11-26

悩み

こういうやり辛そうな文字列から,不要なコメントのみを削除したい.
が,この場合,ハッシュ記号 (#) の全てを消すとまずい (引用符内にあるハッシュを削除しないようにしなくてはならない…).

cmd = """
# これは消さなきゃダメ
x <- 3  # これは消さなきゃダメ

paste('# これは消しちゃダメ')
paste('''
    # これは消しちゃダメ
''')
paste('"# これは" 消しちゃダメ')
"""

方法

ハッシュの位置 (hash_ids) を取得した後,さらに絞り込みをかけ,コメントを示すハッシュの位置 (comment_ids) を取得する.

from typing import List
from copy import copy
import numpy as np


def count_quote_marks(x: str) -> List[int]:
    """各種引用符の数を数える"""
    n_tquotes = x.count('\'\'\'')
    n_tdquotes = x.count('\"\"\"')
    n_quotes = x.count('\'') - 3 * n_tquotes
    n_dquotes = x.count('\"') - 3 * n_tdquotes
    return [n_quotes, n_dquotes, n_tquotes, n_tdquotes]


def get_comment_ids(cmd: str) -> List[int]:
    """「コメントを示す」ハッシュのインデックスを取得"""
    # quotes, double quotes, triple quotes, triple double quotesの数を保持するリスト
    quotes_counts = np.zeros(4, dtype=int)

    # ハッシュ (#) の位置を返すジェネレーター
    hash_ids = (i for i, elem in enumerate(cmd) if '#' in elem)

    # hash_idsのうち,引用符内に無いハッシュのインデックスをcomment_idsとする
    prev_i = 0
    comment_ids = []
    for i in hash_ids:
        sliced = cmd[prev_i: i]
        quotes_counts += np.array(count_quote_marks(sliced))

        # 全quotes_countsが偶数 <=> 引用符外にあるハッシュ
        if np.sum((quotes_counts) % 2) == 0:
            comment_ids.append(i)

        prev_i = i

    return comment_ids


def get_return_ids(cmd: str) -> List[int]:
    """改行記号\nを取得"""
    return [i for i in range(len(cmd)) if cmd[i: i + 1] == '\n']


def delete_useless_comments(cmd: str) -> str:
    """不要なコメントを削除する"""
    cmd = copy(cmd)

    comment_ids = get_comment_ids(cmd)
    return_ids = get_return_ids(cmd + '\n')

    next_return_ids = []  # ハッシュ直後の改行コードを取得
    for index in comment_ids:
        next_return_ids.append([i for i in return_ids if i > index][0])

    # 後ろからcmdを削っていかないとインデックス指定が面倒なので
    for i, j in zip(reversed(comment_ids), reversed(next_return_ids)):
        cmd = cmd[:i] + cmd[j:]
    return cmd

結果

いけた.

print(cmd, end='\n' + '=' * 50 + '\n')
print(delete_useless_comments(cmd))
# これは消さなきゃダメ
x <- 3  # これは消さなきゃダメ

paste('# これは消しちゃダメ')
paste('''
    # これは消しちゃダメ
''')
paste('"# これは" 消しちゃダメ')

==================================================


x <- 3  

paste('# これは消しちゃダメ')
paste('''
    # これは消しちゃダメ
''')
paste('"# これは" 消しちゃダメ')

余談

「pypeRに引き渡すコマンドにコメント#が含まれているとpypeRがフリーズする」という悩みがきっかけだったので,cmdがRのスクリプトになっている…

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1