0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Posted at
"""
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)

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?