跳转到内容

User:深鸣/gadgets/wiki ref name.py

维基百科,自由的百科全书
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import re
import tldextract


def extract_main_domain(url: str) -> str:
    """
    使用 tldextract 提取 URL 的主域名。
      例如:https://news.gamme.com.tw/xxx
        subdomain = 'news'
        domain    = 'gamme'
        suffix    = 'com.tw'
      返回 domain -> 'gamme'
    如果解析失败则返回空字符串。
    """
    ext = tldextract.extract(url)
    return ext.domain or ""


def get_ref_name_for_cite_facebook(inner_content: str) -> str:
    """
    处理形如 {{Cite Facebook|...|2016|10|17|...}} 的日期,
    并生成形如 facebook_20161017 的 ref name。
    """
    # 找到 {{Cite Facebook ...}} 整个模板内容
    # 例如:{{Cite Facebook|TongLiComic|東立出版社|2016|10|17|1465526213475042}}
    # 我们要提取第4,5,6(或第3,4,5)个参数做 yyyy, mm, dd
    # 这里简单用正则找出 "Cite Facebook" 后的所有用 | 分隔的内容
    m = re.search(
        r"{{\s*Cite\s*Facebook\s*\|([^{}]+)}}", inner_content, flags=re.IGNORECASE
    )
    if not m:
        return ""
    # 拿到 "TongLiComic|東立出版社|2016|10|17|1465526213475042"
    param_string = m.group(1).strip()
    # 分割
    parts = [p.strip() for p in param_string.split("|")]
    # 假设日期应为 parts[2], parts[3], parts[4] => year, month, day
    # 参考:https://zh.wikipedia.org/wiki/Template:Cite_Facebook
    # 示例: {{Cite Facebook|TongLiComic|東立出版社|2016|10|17|1465526...}}
    #       0: TongLiComic
    #       1: 東立出版社
    #       2: 2016
    #       3: 10
    #       4: 17
    #       5: 1465526...
    # => year=parts[2], month=parts[3], day=parts[4]
    if len(parts) < 5:
        return ""  # 参数不够,无法解析

    year = parts[2]
    month = parts[3].zfill(2)  # 若只有 '1' -> '01'
    day = parts[4].zfill(2)

    date_str = year + month + day  # e.g. "20161017"

    return f"facebook_{date_str}"


def get_ref_name_for_cite_tweet(inner_content: str) -> str:
    """
    处理 {{Cite tweet |date=YYYY-MM-DD|...}} 生成 tweet_YYYYMMDD。
    参考:https://zh.wikipedia.org/wiki/Template:Cite_tweet
    """
    # 简单用正则找 date= 后的内容
    date_match = re.search(
        r"\|\s*date\s*=\s*(.*?)\s*(?=\||}}|$)", inner_content, flags=re.IGNORECASE
    )
    if not date_match:
        return ""
    date_val = date_match.group(1).strip()  # e.g. "2018-12-24"
    if not date_val:
        return ""
    date_str = date_val.replace("-", "")  # "20181224"
    return f"tweet_{date_str}"


def get_ref_name_normal(url: str, date: str, domain_counter: dict) -> str:
    """
    一般情况:使用 tldextract 获取主域名 + date(若有) 或 + 序号(若无)。
    """
    domain = extract_main_domain(url)
    if not domain:
        domain = "unknown"

    # 如果有 date,就用 domain+date
    if date:
        date_str = date.replace("-", "")  # 2020-01-01 -> 20200101
        return f"{domain}_{date_str}"
    else:
        domain_counter[domain] = domain_counter.get(domain, 0) + 1
        return domain + str(domain_counter[domain]).zfill(2)


def process_wikitext(text: str) -> str:
    """
    处理整个 Wikitext,把没有 name= 的 <ref> 补上 name。
    特殊处理:Cite Facebook / Cite tweet。
    """
    domain_counter = {}

    # 匹配所有 <ref>...</ref>(非贪婪)
    ref_pattern = re.compile(r"(<ref[^>]*?>.*?</ref>)", flags=re.DOTALL)

    def replace_ref(m):
        original_ref = m.group(1)

        # 若已有 name=,跳过
        if re.search(
            r'<ref[^>]*?\bname\s*=\s*["\']', original_ref, flags=re.IGNORECASE
        ):
            return original_ref

        # 拿到去掉 <ref ...> 和 </ref> 的内部内容
        inner_content = re.sub(
            r"^<ref[^>]*?>\s*|\s*</ref>$", "", original_ref, flags=re.DOTALL
        )

        # 先判断是否是 Cite Facebook
        if re.search(r"{{\s*Cite\s*Facebook", inner_content, flags=re.IGNORECASE):
            ref_name = get_ref_name_for_cite_facebook(inner_content)
            if not ref_name:
                # 如果解析失败,再降级为普通逻辑
                ref_name = "facebookUnknown"

        # 再判断是否是 Cite tweet
        elif re.search(r"{{\s*Cite\s*tweet", inner_content, flags=re.IGNORECASE):
            ref_name = get_ref_name_for_cite_tweet(inner_content)
            if not ref_name:
                ref_name = "tweetUnknown"

        else:
            # 普通逻辑:通过 url= / date=
            # 提取 url=...、date=...
            url_match = re.search(
                r"\|\s*url\s*=\s*(.*?)\s*(?=\||}}|$)",
                inner_content,
                flags=re.IGNORECASE,
            )
            date_match = re.search(
                r"\|\s*date\s*=\s*(.*?)\s*(?=\||}}|$)",
                inner_content,
                flags=re.IGNORECASE,
            )

            url_val = url_match.group(1).strip() if url_match else ""
            date_val = date_match.group(1).strip() if date_match else ""

            ref_name = get_ref_name_normal(url_val, date_val, domain_counter)

        # 构造新的 <ref name="xxx">
        # 拿到开头的 <ref ...>
        opening_tag_match = re.match(r"^(<ref)([^>]*?)>", original_ref, flags=re.DOTALL)
        if not opening_tag_match:
            return original_ref  # 理论上不会失败

        ref_open_tag = opening_tag_match.group(1)  # <ref
        ref_other_attrs = opening_tag_match.group(2)  # 可能含 group="xx" 等

        new_open_tag = f'{ref_open_tag} name="{ref_name}"{ref_other_attrs}>'
        # 拼回 inner_content + </ref>
        new_ref = new_open_tag + inner_content + "</ref>"

        return new_ref

    return ref_pattern.sub(replace_ref, text)


def main():
    input_file = "input_wikitext.txt"
    output_file = "output_wikitext.txt"

    with open(input_file, "r", encoding="utf-8") as fin:
        original_text = fin.read()

    processed_text = process_wikitext(original_text)

    with open(output_file, "w", encoding="utf-8") as fout:
        fout.write(processed_text)


if __name__ == "__main__":
    main()