LoginSignup
14
23

More than 3 years have passed since last update.

複数の語句をまとめて置換する

Last updated at Posted at 2019-06-10

既定の関数では、1つの語句を置換するText.Replace()しか見当たらないようなので、まとめて複数語句を消したり、置換するコードを書いてみました。
2019/9/14追記:パターン2にもっと短いバージョンを書き加えました。

サンプルデータ

詳細エディタに貼ってみてください。

サンプルテキスト
let
    Source = "H4sIAAAAAAAEAK2Wz09jVRTH9/xVFjOJrkxYaVyYTGbhwsRMDLp+p0anQEtLB5mNsfPSIC0Q6DQF+VEIpHR40hJHCYbYcXDMQAFJSnRhRhd+znnvta/VGBemeX333XvuOd/zPT/ulR+lIBUnJuE7JxdSl5JcicfXnKyIK2W5YW5ODlnVcZF3W1pSkaozzNsVT7b7pJupETlm/XAsh952oCvc30z/Isfp3zK/yhpfVVkUL/mBzIcah5xXFEb2Zd+mohNjW0M2mNljZU12eOp9ajooqAGhJatSV/nJnzF/7sQyL1C/n01K8d6l7DqxIWc0/m48Gx+NJ+Ij8dvxEScWf1PfNh4e+rdF50MFWJ9ZkH2YuJTazL0o9lEwP9cHjCWWm/JUHkGfWt9ipg5lPaKO8WgOieeybCQ9ZgcPo7xsy3HqcznFz9p4DD9mA9JfSD5EEeGULRuSn9hCsWvIcDv5AEoKjJ9JDfOd1BlArlBdR40hVloTWajDSKqNZB3z6g2UGtCufrSXlHj1MIf4NsifYuorM11g7pyvTShAbnA5x68VLoeyveUzWTIaS+KqQCjtC3gmsBMRUPoTjZ6bAO/gSrUXBuJPGuNyk5nq/xLvKK8RXhqZN+SYXBjIgz7mPHDrUwn3AyfjQHqkvLI36ffkO3xoy950UflIvybfD8a7TnxhwolpNOUbYumS4ss6o4UwPWc4d2yThzKluTH1iXjZPxUhyGctNr4P4ahgyVVjxpKOZGtHanHm7ek/ULavhsnTHa2sgVKnxrTYpXP/o+lEkK9+wPrKImCEvHxoAlU58x0bDeqlq9XGBcY32C1r0DPfmn03SFs2Mp+jso1HSCj2ZC1UpyRgB4PL1g20CwSmNqwotYMVUURMneFEldI8sApqdDcrk3nezZD8Ep/9SdDlQK5hYAV7XzNDkYDHw0Qx0iZRPXY02AgnDqZetwApg2U8nJeGhnbyjhYzOoLQwGTNL70TM/0I8cBdYNmWaIq4Ud5P+OW7zcj+gfOYkRotmZ5ei+rcjwehm1cFPmXq9awTiy5BzF5AY9Askg+zL+nQe5O3BqRWe2FGCdY8a+V9gkaQ4nOpdX2eUfmaVG6U/Qjj5mUQCWCf8uvMbNIJPGyuWapXUUKvx34xGO37rbB3QhD2CjFbUkjWLX7QWvTjkb2RXfHGPvYLx0/SBflJk6476h4Gt4xxTZij9Drx06IM86RAdri+M+kj/yybKI+/ipOLkP5k8v2wGQ8eH62ehZ7np30ZpF9PoHGROFSsMWgf6bYAxTLzJUzUohZa1l/Vj2uWtJy29RzgMHJlHcb1GMrrfYAz4e74F3poovTEohHz32EnYlS1atnyD1piSYNIvwO4Fu6Tm6m7lEWZaNLSEuuW5FW9L7CqAXT/i4d5YlBhg7U+zYTgmItcGOx0Yss1mGoRZUWZy06B4Bp8qzDb372L3Ht2wdxh/xWFduFLcF0os2PBv1CQrX7YOtO/y3zYbzXUpnnXArzWf/RgnQuHtP3EyWt9RMszSI1AbxO9rnF5ET1Z7FhrygHsLv1jgtC2rElZNlnjguwtPeD/Tmp94K7gkwihY+fSmSgkP6UH5MyPAJse8/Hb/ultb1SallOQXPntafJwMAgVu2gEHS29wuKlVA1V2E73zLimhZdNZrYevOWvfLZpVPYc/QvHXnlEmgoAAA==",
    Custom1 = Binary.Decompress( Binary.FromText(Source),Compression.GZip),
    Custom2 = Text.FromBinary(Custom1,932)
in
    Custom2

image.png

パターン1:指定した語句を全部抹消したい。

消去対象のテキストのリスト

消去リスト
let
    Source = "WyJcdTY4NDNcdTU5MmFcdTkwY2UiLCJcdTMwNGFcdTMwNThcdTMwNDRcdTMwNTVcdTMwOTMiLCJcdTMwNGFcdTMwNzBcdTMwNDJcdTMwNTVcdTMwOTMiLCJcdTY4NDMiXQ==",
    Custom1 = Binary.FromText(Source),
    #"Imported JSON" = Json.Document(Custom1,932)
in
    #"Imported JSON"

image.png

コード

= List.Accumulate(消去リスト,
                  サンプルテキスト,
          (state,current)=>Text.Replace(state,current,"")
 )

完成図

狙い通り主語が登場人物が消えています。
image.png

パターン2:指定した表のとおり、置換したい。

あらかじめ変換表の形で用意しておいてから、それにしたがって、変換します。

語句の変換表

t_指示テーブル
let
    Source = "H4sIAAAAAAAEAI2QOw6AIBAF70JtgSxfryIWuMINqIx3dxcrDRqbyf7ekDDvIlazlhyrRzuKiVrrNdAwqBRrkJjFQENXLN1Y2FZaFY/tEuSmmQWZON5Sx9Bxg9SJaXyrW9oYZoD3d5yC9O1zstXqn++Z6rv5H74cWV0Ux3IClZSxMUcBAAA=",
    Custom1 = Binary.Decompress(Binary.FromText(Source),Compression.GZip),
    #"Imported JSON" = Table.FromRecords(Json.Document(Custom1,932))
in
    #"Imported JSON"

image.png

コード(旧)

あとで取り出しやすいように、一度関数(fx_複数置換)を仕上げてから、実行させています。

q_複数置換
[fx_複数置換=
 (対象 as text,指示表 as table,C1 as text,C2 as text)=>

    List.Last( List.Generate(()=>[id=0,vstr=対象],
                             each [id]<=Table.RowCount(指示表),
                             each [id=[id]+1,
                                   vstr=Text.Replace([vstr],
                                                  Record.Field(指示表{[id]},C1),
                                                  Record.Field(指示表{[id]},C2)
                                         )
                                  ],
                             each [vstr]
                )
    ),
 実行=fx_複数置換(サンプルテキスト,t_指示テーブル,"対象","置換後")
][実行]

コード(新)

以前、コンペで考えたときに、もっと簡単な方法を思いついていましたが、載せるのを忘れてました。
たった、これだけです。
※空のクエリを作って、数式バーに貼ってください。

q_複数置換Ver2
= List.Accumulate(
  Table.ToRows(t_指示テーブル), //リストの各項目を用いた繰り返し処理。
    サンプルテキスト,        //初項。最初のxはこれになる。
   (x,y)=>Text.Replace(x,y{0},y{1}) //{0},{1}はリストの項目の取り出し方の記法。
 )

Ver2の解説

みんな大好きList.Accumulate関数を使いました。
第一引数にあるリストの最初から、最後までの全項目を使って、何かやるときに使います。
公式の雪嶺ではstate,currentで関数を作ってますけど、要は順番と名前を間違えなければ、何でもいいんです。
※僕はxとyとか、aとbにすることが多いです。日本語で、「先」と「後」でもいいわけです。

図解
Table.ToRows関数の結果の様子
image.png

List.Accumulate関数の進行の様子

x y 処理後の結果
1周目 サンプルテキストの中身 桃太郎 (桃太郎⇒ピーチ太郎置換後の文字列)
2周目 1周目の処理後の結果 おじいさん (さらに、おじいさん⇒お爺置換後の文字列)
3周目 2周目の処理後の結果 おばあさん (さらに、おばあさん⇒おばあ 置換後の文字列)
4周目 3周目の処理後の結果 (さらに、桃⇒モモ置換後の文字列)

公式の記事はこちら。(いずれも英語)
List.Accumulate - PowerQuery M | Microsoft Docs

Expressions, values, and let expression内のリストの箇所

List.Accumulate関数を本格的に使っている @PowerBIxyz さんの記事はこちら。
僕もこの記事を書いていただいてから、使い始めました。
Power Query の List.Accumulate 関数ってなんだよー - Qiita

完成図

変換されてますね。
image.png

おまけ:パターン1別法

Splitter関数群にちょうどいいものがあるので、こちらの方がスッキリします。
ただ、僕は忘れそうだなと思ったので、Splitterを別法としました。

Text.Combine(
 Splitter.SplitTextByEachDelimiter(消去リスト)(サンプルテキスト)
)

参考:レファレンス
Splitter.SplitTextByEachDelimiter | Microsoft Docs

14
23
1

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
14
23