#概要
やりたかった正規表現による抽出(それ自体繰り返しされるグループを抽出)は(おそらく)(正規表現だけでは)できないということがわかった。その代わり目的は正規表現においては先読みによる置換で達成できるが、GASはサポートしていない。splitなどで代替するのが良いか。
#やりたかったこと
spreadsheetにある、
παρά (+gen) from, by; (+dat) with; (+acc) beside = 194
という文字列から
παρά (+gen) (+dat) (+acc)
という文字列を得たい。
#やったこと
- spreadsheetの関数で
regexextract
を使う。 - apps scriptで
re.exec(text)
してみる。 - 先読み!
- splitゴリ押し
#結果
##SparedSheetで頑張る!
=regexextract(A1,"([^ ]+)(?:(?:[^\(]+)(\(.*?\)))*")
これはだめ。セルにエラー(#REF!)が出る
Array result was not expanded because it would overwrite data in A1.```
ちなみに
```javascript
=regexextract(A1,"([^ ]+)(?:(?:[^\(]+)(?:\(.*?\)))*")
とすればπαρά
だけが出る。要するにマッチしてキャプチャする要素が一つだけなら行けるらしい。
それ以上の時はApps Scriptを書けばいいのかと思って次に、
##Apps Scriptで頑張る!
const text = "εἰς (εἷς_1) (+acc) into, to, for (prep) = 1767";
/([^ ]+)(?:(?:[^\(]+)(\(.*?\)))*/.exec(text).forEach(function(element){
Logger.log(element);
});
を走らせてみる。しかし結果は、
[20-08-03 11:18:33:886 JST] εἰς
[20-08-03 11:18:33:888 JST] (prep)
となる。これはcaptureを全てにしてみると何が起きてるかわかる。
/([^ ]+)(([^\(]+)(\(.*?\)))*/.exec(text).forEach(function(element){
Logger.log(element);
});
とすると
[20-08-03 11:21:27:879 JST] εἰς (εἷς_1) (+acc) into, to, for (prep)
[20-08-03 11:21:27:881 JST] εἰς
[20-08-03 11:21:27:882 JST] into, to, for (prep)
[20-08-03 11:21:27:883 JST] into, to, for
[20-08-03 11:21:27:885 JST] (prep)
となる。要するにcapturingは最後の結果しか保持してくれない。後方参照について何か誤解していたみたいだ。
##先読みで頑張る!
正規表現のこといろいろ調べてたらなんか先読みあと読みって概念があるらしいことに気づいて、これ使えるんじゃね?って思ってやったら...
###GASのマニュアル
https://support.google.com/docs/answer/3098245
ここに
メモ
Google サービスでは RE2 正規表現を使用しています。Google スプレッドシートでは、Unicode 文字クラスのマッチング以外の RE2 を使用できます。詳しくは、RE2 正規表現の使い方についての説明をご覧ください。
とある。
そしてRE2では、
https://github.com/google/re2/blob/master/doc/syntax.txt
(?=re) | before text matching «re» NOT SUPPORTED |
---|---|
(?!re) | before text not matching «re» NOT SUPPORTED |
(?<=re) | after text matching «re» NOT SUPPORTED |
(?<!re) | after text not matching «re» NOT SUPPORTED |
だそうです(シュン)。
##splitゴリ押し
結局これだよ
function EXTRACT_WORD_INFORMATION(string) {
const splitedBySpace = string.split(" ");
const word = splitedBySpace[0];
const followings = splitedBySpace.slice(1);
const informations = followings.filter(function(element){
return /\(.+\)/.test(element);
});
const result = word + " " + informations.join(" ");
Logger.log(result);
return result;
}
#教訓
正規表現だけに頼ってはだめ。