LoginSignup
0
0

More than 3 years have passed since last update.

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

Posted at
"""
29. 国旗画像のURLを取得する
テンプレートの内容を利用し,国旗画像のURLを取得せよ.(ヒント: MediaWiki APIのimageinfoを呼び出して,ファイル参照をURLに変換すればよい)
"""

import json
import re
import urllib.parse
import urllib.request

import requests

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'
        - []        Used to indicate a set of characters. [(+*)] will match any of the literal characters '(', '+', '*', or ')'.
        - ^\|       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
    """
    「'''グレートブリテン'''」->「グレートブリテン」
    """
    pattern = re.compile(
        r"""
            (\'{2,5})   # 2〜5個の'(マークアップの開始)
            (.*?)       # 任意の1文字以上(対象の文字列)
            (\1)        # 1番目のキャプチャと同じ(マークアップの終了)
        """,
        re.MULTILINE | re.VERBOSE,
    )
    target = pattern.sub(r"\2", target)  # 2番目のグループを全体に切り替える

    """
    and27: remove internal link and file
        [[ロンドン]] -> ロンドン
        [[イギリスの首相|首相]] -> 首相
        [[ファイル:Royal Coat of Arms of the United Kingdom.svg|85px|イギリスの国章]] -> イギリスの国章
    """
    pattern = re.compile(
        r"""
            \[\[        # '[['(マークアップの開始)
            (?:         # キャプチャ対象外のグループ開始
                [^|]*?  # '|'以外の文字が0文字以上、非貪欲
                \|      # '|'
            )*?          # グループが0以上、非貪欲
            ([^|]*?)    # キャプチャ対象、'|'以外が0文字以上、非貪欲(表示対象の文字列)
            \]\]        # ']]'(マークアップの終了)
        """,
        re.MULTILINE | re.VERBOSE,
    )
    target = pattern.sub(r"\1", target)  # 1番目のグループを全体に切り替える

    # ans28: remove markups as many as possible
    # Remove {{}}
    """
    {{lang|fr|Dieu et mon droit}} -> Dieu et mon droit
    {{仮リンク|リンゼイ・ホイル|en|Lindsay Hoyle}} -> Lindsay Hoyle
    """
    pattern = re.compile(
        r"""
            \{\{    # '{{'(マークアップの開始)
            .*?     # 文字が0文字以上、非貪欲
            (?:
                [^|]*?
                \|
            )*?
            ([^|]*?)
            \}\}        # '}}'(マークアップの終了)
        """,
        re.MULTILINE | re.VERBOSE,
    )
    target = pattern.sub(r"\1", target)

    # Remove <ref> pattern 1
    """
    "6643万5600<ref>{{Cite web|url=https://www.ons.gov.uk/peoplepopulationandcommunity/populationandmigration/populationestimates|title=Population estimates - Office for National Statistics|accessdate=2019-06-26|date=2019-06-26}}</ref>",
    ->
    "6643万5600",
    """
    pattern = re.compile(r"<ref.*?</ref>")
    target = pattern.sub(r"", target)

    # Remove <ref> pattern 2
    """
    ('2兆3162億<ref name="imf-statistics-gdp" />', "2兆3162億"),
    """
    pattern = re.compile(
        r"""
            <           # '<'(マークアップの開始)
            \/?         # '/'が0か1出現(終了タグの場合は/がある)
            ref         # 'ref'
            [^>]*?      # '>'以外が0文字以上、非貪欲
            >           # '>'(マークアップの終了)
        """,
        re.MULTILINE + re.VERBOSE,
    )
    target = pattern.sub(r"", target)  # no space

    # Replace <br> with ' ', the 国歌 is easier to read
    """
    "God Save the Queen}}{{en icon}}<br />神よ女王を護り賜え<br />{{center|ファイル:United States Navy Band - God Save the Queen.ogg}}"
    ->
    "God Save the Queen}}en icon 神よ女王を護り賜え ファイル:United States Navy Band - God Save the Queen.ogg",
    """
    pattern = re.compile(
        r"""
            <           # '<'(マークアップの開始)
            \/?         # '/'が0か1出現(終了タグの場合は/がある)
            br         # 'br'
            [^>]*?      # '>'以外が0文字以上、非貪欲
            >           # '>'(マークアップの終了)
        """,
        re.MULTILINE + re.VERBOSE,
    )
    target = pattern.sub(r" ", target)  # with space

    # # Premove <br>, <ref> pattern 2
    # """
    # ("成立<br />(1707年合同法)", "成立(1707年合同法)"),
    # ('2兆3162億<ref name="imf-statistics-gdp" />', "2兆3162億"),
    # """
    # pattern = re.compile(
    #     r"""
    #         <           # '<'(マークアップの開始)
    #         \/?         # '/'が0か1出現(終了タグの場合は/がある)
    #         [br|ref]    # 'br'か'ref'
    #         [^>]*?      # '>'以外が0文字以上、非貪欲
    #         >           # '>'(マークアップの終了)
    #     """,
    #     re.MULTILINE + re.VERBOSE,
    # )
    # target = pattern.sub(r"", target)

    # Remove external link [http://xxxx] 、[http://xxx xxx]
    """
    [http://www.example.org] -> ''
    [http://www.example.org 表示文字] -> '表示文字'
    """
    pattern = re.compile(
        r"""
            \[http.?:\/\/ # '[http://'(マークアップの開始) or https
            (?:         # キャプチャ対象外のグループ開始
                [^\s]*? # 空白以外の文字が0文字以上、非貪欲
                \s      # 空白
            )?          # グループ終了、このグループが0か1出現
            ([^]]*?)    # キャプチャ対象、']'以外が0文字以上、非貪欲(表示対象の文字列)
            \]          # ']'(マークアップの終了)
        """,
        re.MULTILINE + re.VERBOSE,
    )
    target = pattern.sub(r"\1", target)

    return target


def get_flag_url(query: str) -> str:
    # Send request to MediaWiki
    request = urllib.request.Request(query, headers={"User-Agent": "Xu"})
    connection = urllib.request.urlopen(request)

    # get json data
    data = json.loads(connection.read().decode())
    utils.save_json(data, "29_wiki_api.json")

    # get URL
    url = data["query"]["pages"].popitem()[1]["imageinfo"][0]["url"]

    return url


def get_flag_url_with_requests(query: str) -> str:
    data = requests.get(query)
    return re.search(r'"url":"(.+?)"', data.text).group[1]


# 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, ans27, ans28
result = {k: remove_markup(v) for k, v in fields.items()}  # See 26_no_markup.json

# ans29
flag_name = result["国旗画像"]
query = (
    "https://www.mediawiki.org/w/api.php?"
    + "action=query"
    + "&titles=File:"
    + urllib.parse.quote(flag_name)
    + "&format=json"
    + "&prop=imageinfo"
    + "&iiprop=url"
)
url1 = get_flag_url(query)
url2 = get_flag_url_with_requests(query)
print(url1)
assert url1 == url2

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