言語処理100本ノック(2020): 27

```py
"""
27. 内部リンクの除去
26の処理に加えて，テンプレートの値からMediaWikiの内部リンクマークアップを除去し，テキストに変換せよ（参考: マークアップ早見表）．
"""

import json
import re

import utils


def get_uk_text(path):
    with open(path) as f:
        for line in f:
            line_data = json.loads(line)
            if line_data["title"] == "イギリス":
                data = line_data
                break
    return data["text"]


def get_basic_info(string: str) -> str:
    """Get basic information section
    """
    pattern = re.compile(
        r"""
            ^\{\{基礎情報.*?$   # '{{基礎情報'で始まる行
            (.*?)       # キャプチャ対象、任意の0文字以上、非貪欲
            ^\}\}$      # '}}'で終わる行
        """,
        re.MULTILINE | re.DOTALL | re.VERBOSE,
    )

    return re.findall(pattern, string)[0]


def get_content(string: str) -> list:
    r"""
    https://docs.python.org/3/library/re.html#regular-expression-syntax

    RE:
        - re.X (re.VERBOSE)     Allow us add command to explain the regular expression
        - re.M (re.MULTILINE)   Apply match to each line. If not specified, only match the first line.
        - re.S (re.DOTALL)      Allow to recognize '\n'
        - ^\|       String begin with |
        - ?         Causes the resulting RE to match 0 or 1 repetitions

        - *?        The '*' qualifier is greedy.
                    Adding ? after the qualifier makes it perform the match in non-greedy or minimal fashion; as few characters as possible will be matched.
                    e.g. <.*> is matched against '<a> b <c>'
                    e.g. <.*?> will match only '<a>'

        - (...)     Matches whatever regular expression is inside the parentheses,
        - (?=...)   Matches if ... matches next, but doesn’t consume any of the string. This is called a lookahead assertion.
                    For example, Isaac (?=Asimov) will match 'Isaac ' only if it’s followed by 'Asimov'.
        - (?:...)   A non-capturing version of regular parentheses.

    Input:
        - '|国章リンク =（[[イギリスの国章|国章]]）'
    Return:
        - {'国章リンク': '（[[イギリスの国章|国章]]）'}
    """
    pattern = re.compile(
        r"""
            ^\|         # '|'で始まる行
            (.+?)       # キャプチャ対象（フィールド名）、任意の1文字以上、非貪欲
            \s*         # 空白文字0文字以上
            =
            \s*         # 空白文字0文字以上
            (.+?)       # キャプチャ対象（値）、任意の1文字以上、非貪欲
            (?:         # キャプチャ対象外のグループ開始
                (?=\n\|)    # 改行+'|'の手前（肯定の先読み）
                |           # または
                (?=\n$)     # 改行+終端の手前（肯定の先読み）
            )           # グループ終了
            """,
        re.MULTILINE | re.DOTALL | re.VERBOSE,
    )
    result = re.findall(pattern, string)
    return {k: v for k, v in result}  # dict is ordered when using python 3.7


def remove_markup(target: str) -> str:
    # ans26
    # Remvoe highlight markup
    # Using the 「グレートブリテン」to replace「'''グレートブリテン'''」
    pattern1 = re.compile(
        r"""
            (\'{2,5})   # 2〜5個の'（マークアップの開始）
            (.*?)       # 任意の1文字以上（対象の文字列）
            (\1)        # 1番目のキャプチャと同じ（マークアップの終了）
        """,
        re.MULTILINE | re.VERBOSE,
    )
    target = re.sub(pattern1, r"\2", target)

    # and27
    # Remove link markup
    """
    [[ロンドン]] -> ロンドン
    [[イギリスの首相|首相]] -> 首相
    [[ファイル:Royal Coat of Arms of the United Kingdom.svg|85px|イギリスの国章]] -> イギリスの国章

    [] -> Used to indicate a set of characters. [(+*)] will match any of the literal characters '(', '+', '*', or ')'.
    """
    pattern2 = re.compile(
        r"""
            \[\[        # '[['（マークアップの開始）
            (?:         # キャプチャ対象外のグループ開始
                [^|]*?  # '|'以外の文字が0文字以上、非貪欲
                \|      # '|'
            )*?          # グループが0以上、非貪欲
            ([^|]*?)    # キャプチャ対象、'|'以外が0文字以上、非貪欲（表示対象の文字列）
            \]\]        # ']]'（マークアップの終了）
        """,
        re.MULTILINE | re.VERBOSE,
    )
    target = re.sub(pattern2, r"\1", target)

    return target


# and20
uk_text = get_uk_text("jawiki-country.json")  # See uk_text.txt

# ans25
basic_info = get_basic_info(uk_text)
fields = get_content(basic_info)  # See 25_en_basic_info.json

# ans26, and27
result = {k: remove_markup(v) for k, v in fields.items()}  # See 26_no_markup.json
# "国章画像": "[[ファイル:Royal Coat of Arms of the United Kingdom.svg|85px|イギリスの国章]]",
print(result["国章画像"])
utils.save_json(result, "27_no_link.json")


# Test for 27
data = [
    ("[[ロンドン]]", "ロンドン"),
    ("[[イギリスの首相|首相]]", "首相"),
    ("[[ファイル:Royal Coat of Arms of the United Kingdom.svg|85px|イギリスの国章]]", "イギリスの国章"),
    (
        "{{lang|fr|[[Dieu et mon droit]]}}<br />（[[フランス語]]:[[Dieu et mon droit|神と我が権利]]）",
        "{{lang|fr|Dieu et mon droit}}<br />（フランス語:神と我が権利）",
    ),
]


pattern2 = re.compile(
    r"""
            \[\[        # '[['（マークアップの開始）
            (?:         # キャプチャ対象外のグループ開始
                [^|]*?  # '|'以外の文字が0文字以上、非貪欲
                \|      # '|'
            )*?          # グループが0以上、非貪欲
            ([^|]*?)    # キャプチャ対象、'|'以外が0文字以上、非貪欲（表示対象の文字列）
            \]\]        # ']]'（マークアップの終了）
        """,
    re.MULTILINE | re.VERBOSE,
)

for target, answer in data:
    assert answer == re.sub(pattern2, r"\1", target)

```