読者です 読者をやめる 読者になる 読者になる

Rustでカッコ対応判定

{}, [], ()の3種類について対応の判定をする。あんま分かりやすいコードじゃないですが…

fn valid_braces(s: &str) -> bool {
    let mut v = Vec::new();
    for c in s.chars() {
        if c == '{' || c == '[' || c == '(' {
            v.push(c);
        }
        else
        {
            if v.is_empty() {return false}
            let x = v.pop().unwrap();
            if (x == '(' && c == ')') || (x == '[' && c == ']') || (x == '{' && c == '}') {
                continue;
            }
            return false;
        }
    }
    if !v.is_empty() { return false }
    return true;
}

連続する文字列の中で長さ最大のものを選ぶ in Rust

codewarsより。

入力として、文字列の配列と整数kが与えられる。配列中のk個の連続する文字列を結合し、長さが最大となるものを選びたい。

longest_consec(vec!["zone", "abigail", "theta", "form", "libe", "zas"], 2);
// => "abigailtheta"

文字列配列をstrarr: Vec<&str>として

strarr.window(k).map(|x| x.join("")).collect()

により次の値を得る。

["zoneabigail", "abigailtheta", "thetaform", "formlibe", "libezas"]

この中からmax_by_keyで長さ最大のものを選べばオッケー。

strarr.window(k).map(|x| x.join("")).max_by_key(|x| x.len()).unwrap_or(String::new())

ただしここで問題の制限がかかってくる。最大長の文字列は、最初に見つけたものを選べ、という条件が付いているのだ。max_by_keyを使うと、長さが同じ場合、後の文字列が選ばれる。max_byで条件を指定する必要がある。

PRAWで遊ぶ(Python Reddit API Wrapper)

ここではPRAWでredditの投稿(submission)を取得する。さしあたりread_only=Trueで済むことだけをやっていく。知見が溜まったらbotを作ってもいいかもしれない。

PRAWのドキュメントに載っている最小利用例を引く。(以下の認証情報は本物ではない。あなたが作るプログラムにはhttps://www.reddit.com/prefs/apps から自分でアプリを登録して得たclient_id, client_secretを使う)

reddit = praw.Reddit(client_id='SI8pN3DSbt0zor',
                     client_secret='xaxkj7HNh8kwg8e5t4m6KvSrbTI',
                     password='1guiwevlfo00esyy',
                     user_agent='testscript by /u/fakebot3',
                     username='fakebot3')

# /r/learnpython のホッテントリを10件取得
for submission in reddit.subreddit('learnpython').hot(limit=10):
    print(submission.title)

しかし、認証情報を直書きするのはよくない。ローカルで使う場合は問題ないが、このようなコードを、ブログやgithubなどに公開した場合、登録したアプリが乗っ取られて悪用される恐れが大きい。

コードから認証情報を分離するために、praw.iniファイルを使う。

プログラムが置かれているディレクトリにpraw.iniファイルを作り、重要な情報はそこに隔離しておく。以下のように(認証情報は自分のものに書き換えて)記述する。my_botの部分は自分の好きな名前を記述してよい。

[my_bot]
client_id     = SI8pN3DSbt0zor
client_secret = xaxkj7HNh8kwg8e5t4m6KvSrbTI
username      = 1guiwevlfo00esyy
password      = fakebot3 

これを作っておくとprawの初期化が楽になる。

reddit = praw.Reddit('my_bot',
                     user_agent='my cool user agent')

以上の初期化を前提として、redditオブジェクトを実際に使っていく。

試しに/r/Pythonの24時間以内の投稿をスコアの高い順に表示してみる。

subreddit = reddit.subreddit('Python')
print(f'/r/{subreddit.display_name}')

for submission in subreddit.top('day'):
    print(f'{submission.title} [{submission.score}]')
    print(submission.url)

この日はipython 6.0のリリースがトップだった。

続いて/r/Animeのsubmissionから[Fanart] flairを抽出してみる。

import re

subreddit = reddit.subreddit('Anime')
print(f'/r/{subreddit.display_name}')

for submission in subreddit.top('day', limit=100):
    if re.search(r'\[Fanart\]', submission.title):
        print(f'[{submission.score}] {submission.title}')
        print(submission.url)

/r/Animeのポストは、selfの本文に画像リンクが貼ってあることが多い。また画像アップローダーにimgurがよく使われる。

そこで、上のコードを変更し、selftextからimgurのリンクだけ抽出するコードを書いてみる。

for submission in subreddit.top('day', limit=100):
    if re.search(r'\[Fanart\]', submission.title):
        pattern = r'imgur\.com/(gallery/|a/|)[a-zA-Z\d\.]+'
        matches = re.finditer(pattern, submission.selftext)
        if matches:
            for m in matches:
                print(f'http://{m.group()}')

正規表現がズボラですが、selftextとにらめっこした限り一応抽出できているようなのでこれでよしとしましょう。)

ここまで来ると/r/Animeに投稿されたFanart画像を収集するbotが作れそうですね。/r/Anime/に限らず2次画像が投稿されるsubrreditは多く存在する(NSFWも多い)ようなので、そこらへんのサブレも含めるといいかもしれない。

などと妄想がすこし膨らんだが飽きたので今日はここまで。