MoreBeerMorePower

Power Platform中心だけど、ノーコード/ローコード系を書いてます。

ダブルクォーテーションで囲みがあるCSVをうまくコレクションに取り込む

f:id:mofumofu_dance:20210922014657p:plain

2021/9/21に投稿されたJohn LiuのブログとReza DorraniのYoutube動画を組み合わせて、日本語を含む (ダブルクォーテーションなどで囲まれていたり囲まれていなかったりする) CSVをうまくPower Appsのコレクションに取り込めたので、方法を書いておきます。

References :

johnliu.net

CSVを取り込む

Rezaの動画では、テキストボックスに入力されたCSV (ヘッダーなし) データを、Split()を2回施して入れ子になった配列としてコレクションに格納していました。

(Rezaの動画のすごいところは、それをさらにバルクで編集・削除・コピー・Listsへの登録を行っている点だと思います)

ClearCollect(
 colCSV,
   ForAll( 
      Split(TextInput1.Text, Char(10)),
      Split(Result, ",")
   )
)

大体このような形です。 Char(10)が改行コードなので、各行を分割して、カンマ区切りという想定で ","で再度Splitしています。

これだと、ダブルクォーテーションで囲まれたような列があると対応できません。(例えば"aaaa, bbbb"のようなケースは "aaaabbbb"に分割される)

そこで、正規表現によるCSVのパースを考えます。

正規表現を使った各行のパース

改行コードでSplitが終わったあとの各行にダブルクォーテーションの囲みが含まれているような場合、 John Liuのブログで紹介されているように以下の正規表現で各列の値を取り出すことができます。

"(?:,|^)(""((?:(?:"""")*[^""]*)*)""|[^"",]*|(?:$))"

ここでは、Power Appsでのダブルクォーテーションのエスケープが ""であることを反映しています。

この正規表現ではRegex debuggerによれば2つのサブマッチの結果が得られます。

f:id:mofumofu_dance:20210922012920p:plain

見ると、ダブルクォーテーションで始まるようなケースがGroup[2]に、Group[2]のケース+それ以外の場合がGroup[1]に入ることがわかります。

これを踏まえて、先ほどのコレクションへの追加は以下のように書き直せます。

ClearCollect(
    parsedData,
    ForAll(
        Split(
            TextInput1.Text,
            Char(10)
        ),

        ShowColumns(AddColumns(
            MatchAll(
            ThisRecord.Result,
            "(?:,|^)(""((?:(?:"""")*[^""]*)*)""|[^"",]*|(?:$))"
        ),"val",
        If(!IsBlank(Last(ThisRecord.SubMatches).Value),
            Last(ThisRecord.SubMatches).Value,
            First(ThisRecord.SubMatches).Value
        )
        ),"val")
    )
)

MatchAll()を使うと、結果の.SubMatches に Group[1], Group[2] の結果が格納されます。

MatchAllの部分だけを取り出してみると下図のように、Group[1]とGroup[2]の結果がそれぞれSubMatchesに入っていることがわかります。

f:id:mofumofu_dance:20210922013858p:plain

Group[2]が存在する (=Last(SubMatches).Valueが空でない) 場合にはそちらを採用して、存在しないときにはGroup[1]を採用します。

これを表しているのが

        If(!IsBlank(Last(ThisRecord.SubMatches).Value),
            Last(ThisRecord.SubMatches).Value,
            First(ThisRecord.SubMatches).Value
        )

この部分です。

結局上のコレクションへの追加を使うと、ダブルクォーテーションの囲みを考慮して、CSVの取り込み結果は以下のようになります。

f:id:mofumofu_dance:20210922014222p:plain

上手く空欄もダブルクォーテーションも考慮されてコレクションへ追加されていることがわかるでしょう。

ということで、RegexとSplitを組み合わせるとうまくCSVをコレクションに取り込めるという紹介でした。