もう一人のY君

主にiPhoneのショートカットアプリのレシピやTipsなどを書いています. たまに数学の記事も書きます.

もう一人のY君 MENU  MENU

【iPhoneショートカット】指定ワードを含む行とその次行を取得する【正規表現】

f:id:thetheorier:20210624150719p:plain

 知っておくと便利です.

 前者については「ファイルにフィルタを適用」アクションもあり, オプションも豊富なのでそっちがいいかも.

 

 

ショートカット

ショートカット

  • Apple
  • 仕事効率化
  • 無料

※価格は記事執筆時のものです. 現在の価格はApp Storeから確認ください.

 レビュー時のiOSバージョン : iOS14.6

 

 

スポンサーリンク

 

 

 

いかにして取り出すか

blog.thetheorier.com

 もう1年以上前の投稿ですが, Webページの本文を取り出して必要なデータを処理することを紹介しました.

 しかしここでは「必要なデータまでの行数が固定である」という条件が必要でした.

 もしその情報より手前の行数が変わるよう更新が行われると, 正しく処理できないということになります.

 

 もしその情報が指定ワードを含む同じ行に存在するなら, 一旦分割した後に「ファイルにフィルタを適用」を使うことで解決しますがショートカットの扱い次第では次の行になることもしばしばでです.

 

 そこでヒントになるのが「一致するテキスト」アクションです.

 

f:id:thetheorier:20210624150753p:plain

 例えば画像のように簡単なレシピを使って説明します.

 「入力を要求」で指定ワードを決め, 「テキスト」アクションに改行つきで適当な文字列を入れておき(Webからテキストとして抽出した状態を想定), 「一致するテキスト」で「入力を要求」の内容でマッチさせ, その結果を表示します.

 この「一致するテキスト」アクションは正規表現の機能を内包しています.

 

 

f:id:thetheorier:20210624151714p:plain

 そのためマッチする結果を単純に返すことしかできません.

 ただキーワードを充てがうだけでは不十分です.

 

 

f:id:thetheorier:20210624152041p:plain

 というわけで正規表現を追加します.

 「入力を要求」の結果である「指定入力」の後ろに

 

.*

 

の2文字を追加します.

 ちなみに.は任意の一文字にマッチする正規表現, そして*は直前の文字が0回以上繰り返す最長一致の正規表現です.

 まあ僕も正規表現に詳しくないのでこれらを正確な表現かは自身がないのですが, 大雑把に言えばこの正規表現の組は「(空を含む)すべての文字列にマッチ」します.

 

 

 

f:id:thetheorier:20210624153109p:plain

 これを実行すると, 例えばbと打って続けると結果にbcが帰ってきます.

 .*を加えたことで, マッチしたbに加えその後ろも対象になったわけです.

 ただし改行を含めそれ以降は結果に含まれないという点を忘れてはなりません, そもそも正規表現での改行表記は\nとして別に存在する…という事情もあります.

 

 

 

f:id:thetheorier:20210624153416p:plain

 というわけで例えば更に左にも同じ正規表現を追加すれば…

 

 

f:id:thetheorier:20210624153510p:plain

 指定行の一部だけでその行全体を取得することが可能となります.

 「ファイルにフィルタを適用」の簡易版のようなものですね.

 

 

 見ての通りですが, 対象の行そのものを得ている場合は「完全一致」なので正規表現を使う必要はありません.

 正規表現を使えばマッチさせる行の一部しかわかってなくてもよい…ということです.

 

 

マッチした行の次の行を取得

 ではマッチさせた行の次の行が欲しい場合はどうすればいいのか.

 先程書いたように, .*で好きな文字列にマッチし, 改行の正規表現が\nであることをサッと書きました.

 ならそれを単純に並べれば良いです.

 

 

f:id:thetheorier:20210624154059p:plain

 先程と同じようなレシピですが今度は「一致するテキスト」が

 

「指定入力」.*\n.*

 

に変わります.

 理屈で言えばこの時点で

 

  • キーワードにマッチした行の、キーワード以降の文字列(なのでマッチした行全体とは限らない)
  • マッチした行の次の行全体

 

が得られているはずです.

 

 

f:id:thetheorier:20210624154454p:plain

 よって得られた文字列を改行で分割し, その最後の項目が望む文字列であるはずです.

 

 

f:id:thetheorier:20210624154555p:plain

 実行して確かめたところ, 上記の仮定が正しかったことが確認できます.

 

 

【応用】マッチした行の次の複数行を取得

 上記まではマッチした行の次の一行だけでした, 今度は複数行取り出すことを考えます.

 

 

f:id:thetheorier:20210626080623p:plain

 レシピを改めて作り直しました.

 まず画像にある通り改行を含む適当なテキストを用意し, "hi"を含む行とそのの次の3行分を取得します.

 今回は一致させるための正規表現として

 

hi.*(\n.*){3}

 

と書きます.

 正規表現において括弧()はその中をグループ化するものです, 今回は改行\nと任意の一行/*の組を一つのグループとしているわけですね.

 それに続く{3}は「直前の文字の桁数」を意味します, つまり{3}なら「直前の文字が3回繰り返される」場合にマッチします.

 よって(\n.*){3}は\n.*\n.*\n.*と書いた場合と同じになります.

 

 繰り返しの{}の中身をマジック変数で代入すれば, 好きな行数を指定することができるわけですね.

 もちろん, 「指定した行(の一部)を含むn行」を取得したい場合は{}の中の数がn-1になります.

 

 

f:id:thetheorier:20210626081854p:plain

 というわけで上記のままでは指定行(の一部)が含まれたままです.

 次行のみを取り出したい場合は例えばマッチした結果の先頭のみを「一致したテキスト」でhi.*\nによってマッチさせてから分割し, 後ろの項目を「リストから取得」で取り出す必要があります.

 

 

f:id:thetheorier:20210626082143p:plain

 これを実行してみます.

 マッチさせた時点ではやはり指定行(の一部)が残っていますね.

 後の分割処理によって, 2行目以降が残ります.

 

 

f:id:thetheorier:20210626082424p:plain

 ちなみに指定行を取り出すために「一致したテキスト」でhi.*\nと指定しました.

 この改行\nを無くしてhi.*だけにした場合どうなるか…というと, 改行が残ったために画像のように1行目が空行として残ってしまいます.

 行の内容だけ対象にすればいい…というわけではないので注意が必要です.

 

 

f:id:thetheorier:20210626082800p:plain

 ちなみに指定行を取り除くのにもう一つ, 「テキストを置き換え」アクションを使う方法があります.

 置き換えの対象(灰色で「こんにちは」と書かれている枠)にhi.*\nを入れ, 置き換え先(灰色で「世界」と書かれている枠)には何も書かれていない状態にし, 表示を開いた「正規表現」のスイッチをオンにした状態にします.

 どちらも結局は正規表現を使い, アクション数が2つ少ない1つで済むのでこちらの方が適任でしょうね.

 

 

 このように, ショートカットではあるアクションが別のアクション(の組み合わせ)に置き換えられることがしばしばあります.

 プログラミング言語でもそうなので珍しいことではありませんね.

 

 

 ショートカットは先に述べた通り「ファイルにフィルタを適用」などの検索機能のあるアクション自体は存在しますが, それらで得た項目から相対的に前後の情報を得る簡単な方法が(多分)ありません.

 結果こうして正規表現に頼るしかなさそうです.

 

 だからといって「ファイルにフィルタを適用」が役に立たないわけでもなく, それぞれが異なる性質を持ち, 目的に応じてメリット・デメリットがある…ということです.

 目的に沿うアクションを使えばいいだけの話ですね.

 

 でも正規表現ってわかるようでわからないですね, 難しい…