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()