はじめに
下記の2つの記事の続きで,おまけ的なものですが自分の備忘録のためにも残しておきます(R編がなかなかスタートしないw)。
Slack を用いた授業外ライティング活動の便利ワザ [Google Spreadsheet 編① ]
Slack を用いた授業外ライティング活動の便利ワザ [Google Spreadsheet 編② ]
簡単に何をやっているのかをまとめます。Slack上で授業外ライティング活動をさせ,そこで書かれたものをGoogle Apps Scriptを使ってGoogle Spreadsheetに記録し,そこで個人の1週間あたりの産出語数を学生と共有するということをやっています。大まかな枠組みについては,上記の記事でカバーされていますが,今回は,「ちょっとかゆいところに手が届くといいな」くらいのお話です。
問題の所在
https://twitter.com/tam07pb915/status/1118157873219948545
学生の書いたものを読んでいると,カンマやピリオドの後に半角スペースを入れないで書いているものが頻繁にありました。
Yesterday,I went to the zoo with my family.After that,we went to an Italian restaurant.It was delicious.
みたいな感じのものを想像していただければいいかなと思います。見る人が見たら気持ち悪くてたまらないと思うのですが,おそらくデジタル環境で英語を書くという経験の少なさからこのような英文になってしまうのだと思います。もちろん,タイポのようなことはありうるのですが,それでも一つの投稿で頻発していたり,ある特定の学習者が連続して誤りを犯しているとどうもこれは半角スペースを入れることを知らないのではないか?と考えるようになりました。
手書きでスペースをあける行為と,キーボードやスマートフォン上でスペースバーを押したり,フリック入力時に「空白」と書かれた部分をタップしたりという行為が関連付けられていないのかもしれません。また,日本語では句読点の後にスペースを入れるというルールはありません。
だからといって,彼らの今後の英語使用場面として手書き以外で英語を書くことがないと想定することはできませんし、スペース入れるということも身につけて欲しい(そうじゃない文見たときの気持ち悪さもわかって欲しい)ことではあるのでしつこく言っていかないといけない気がしています。もちろん,気づいたときにはメインのチャンネルにも共有する形でスペースを入れるようにコメントを出してもいます。ただ,そういうことよりもむしろ「リアルなコミュニケーション」の道具として英語を使って教員ともやりとりしてほしいというところもありますので,あまり半角スペース警察にはなりたくありません。
また,授業運営上でも問題はあります。それは,語数のカウントです。語数のカウントは,1語ずつを単語だと認識して数え上げているわけではなく,単語と単語の間に生まれるスペースを基準にして数えています(詳細は上記の過去記事か,「エクセル 単語数える」とかでググって見てください)。つまり,”Yesterday, I”は2語と認識されても,”Yesterday,I”は1語になってしまうというわけです。ピリオドのあとに半角スペースがなく次の文が始まる場合も同様です。私は,「1週間で○○語を書き込むこと」を課題としていますので,あまりにもこのミスが多いと語数のカウントが通常より少なく計算されてしまいます。
解決方法
私が考えつく解決方法は以下のとおりです。一番土方っぽいものから順に,
Googlespreadsheetの書き込みを1セルずつ確認して,ピリオドやカンマのあとにスペースがなければ手作業で足す
Googlespreadsheetの「検索と置換」でピリオドやカンマを探し,ヒットしたものを目視で確認して半角スペースがなければ足す
Googlespreadsheetの「検索と置換」で正規表現を使ってピリオドやカンマのあとにスペースがないものを一括で修正する
Googlespreadsheetでsubstitute関数を使って置換する
1や2はありえないとして,3も問題があります。それは定期的に作業をしないといけないという点です。Googlespreadsheetを使う利点は,一度作業をしたらしばらくの間は放置しておいても勝手に語数が記録されて学生が確認できるという点です。したがって,できれば4で考えたいところです。しかしながら問題は,substitute関数では置換したい対象をうまく持ってこれないという点です。もしも,「すべてのカンマまたはピリオドについて,ピリオドまたはカンマと半角スペースに入れ替える」とすると,正しく使われているところに余計にスペースを入れてしまうことになります。そうなると,スペースの数を基準とする語数カウントがうまくいきません。そこで,正規表現を使う必要が出てきます。なんと,Googlespraedsheetには正規表現が使える次のような関数があります。
REGEXEXTRACT(正規表現で一致する文字列を抽出)
REGEXMATCH(正規表現で一致する文字列があるか検索して真偽値を返す)
REGEXREPLACE(正規表現で一致する文字列を別の文字列に置き換える)
今回の場合は,置き換えが必要なので3番目のREGEXREPLACE関数を使います。正規表現についての詳しい説明はウェブ上にごろごろ転がっているので,以下では詳しい説明はしませんのでご了承ください(注1)。REGEXREPLACE関数は,REGEXREPLACE(検索対象テキスト, 正規表現, 置換)という引数を取ります。最初の検索対象は学生が書き込んだテキストの入っているセルをしていすることになります。では,正規表現の部分はどうすればよいでしょうか。置換したい対象の文字列は,「ピリオドまたはカンマのあとに単語列が続くもの」でした。これを正規表現で表すと次のようにできます。
“(\.|\,)(\w+)”
ここで,カッコでくくってグループ化しているのは,置換するときに元の文字列を使いたいからです。置換は,ピリオドとカンマ,その後に続く単語列はそのままで間にスペースを挟むので,
“$1 $2”
$1は最初にグループ化したものなので,ピリオドまたはカンマ,$2は次にグループ化したものなので,任意の単語列になります。その間に半角スペースが入っています。つまり,次のような関数が完成形になります。
=regexreplace(テキストのあるセル, “(\.|\,)(\w+)”, “$1 $2”)
これで,ピリオドまたはカンマのあとに単語列が続くときは半角スペースを挟む」という作業ができるようになりました。あとは,この関数のセルに対して語数カウントをする数式を適用すればよいわけです。
新たな問題
さて,うまくいったかのようにみえたのですが,実は先程の例を使うと別の問題が発生することに気づきました。それは,半角スペースはあるけれど,それがピリオドやカンマの前 にあるという場合でした。例えば,下記のようなものです。
Yesterday ,I went to the zoo with my family .After that ,we went to an Italian restaurant .It was delicious.
このような用例に対して先程のREGEXREPLACE関数を適用してしまうと,新しく得られるものは次のようになります。
Yesterday , I went to the zoo with my family . After that, we went to an Italian restaurant . It was delicious.
これでは,カンマやピリオドが1つの単語として認識されてしまい,語数のカウントが逆に多くなってしまいます。これを避けるには,「文字列の直後にあるカンマやピリオドの場合には」という条件を加えれば良さそうです(注2)。ということで,改良版は次のようなものです。
=regrexreplace(テキストのあるセル, “(\w+)(\.|\,)(\w+)” , “$1$2 $3”
Googlespreadsheet上で見ると下記画像のようになります。
置換前と置換後のテキストと,それぞれの語数カウントの比較
おまけ(絵文字タグの削除)
slackといえば,絵文字も使えます。絵文字も文字コミュニケーションにおいては重要だという部分もありますし,一切絵文字は使うなというのもおかしな話です。slackから書き出される絵文字は,半角のコロン(:)に挟まれたタグになってテキスト化されます。”:heart:”や”rolling_on_the_floor_laughing”と言った感じです。これが文字列にくっついている場合は特に問題ありません(注3)。しかし,文字列から独立した状態で使われると,絵文字1つが1単語と認識されてしまいます。このことに気づくと,すべての文に絵文字をつけたり,あるいは半角スペースを挟んで絵文字を連続させたりという学生が現れます。昨年度は口頭注意でそれなりにケアしていましたが,どうせREGEXREPLACE関数を使うのだから,絵文字タグも取ってしまえばいいということに気づきました。下記のようにしてあげると,絵文字タグが取れます(注4)。
=regexreplace ( テキストのあるセル , “\:.*?\:” , “” )
実際にGooglespreadsheet上で使うときには,スペースが入っていないことで生じる問題を解決する関数を使った上で,その結果の出力に対してさらに別の列で絵文字タグを取る関数を使うのもありです。むしろ,プログラミング的には良いのだと思います。なぜなら,なにか問題があったときにその問題の原因を探りやすいからです。ただ,入れ子にすれば1列で済みます。
= regexreplace ( regexreplace ( テキストのあるセル , “\:.*?\:” , “” ) , “(\w+)(\.|\,)(\w+)” , “$1$2 $3” )
さらに,語数をカウントする数式にこのREGEXREPLACE関数も入れ込むと…
= ( LEN ( regexreplace ( regexreplace ( テキストのあるセル , “\:.*?\:” , “” ) , “(\w+)(\.|\,)(\w+)” , “$1$2 $3” ) ) – LEN ( SUBSTITUTE ( regexreplace ( regexreplace ( テキストのあるセル , “\:.*?\:” , “” ) , “(\w+)(\.|\,)(\w+)” , “$1$2 $3” ) , ” “ , “” ) ) ) + 1
もうなんだかわけがわからなくなってきましたが,この最後の数式を使えば,新しく列を増やしたりすることなしに語数カウントができるようになっています。
おわりに
この記事では,Googlespreadsheetで正規表現を使って学習者が犯すパンクチュエーションの誤りを直すということの例を示しました。他の媒体(R,Python,サクラエディタ)等で正規表現を使った経験があるのでなんとかなりました。一応ざっと確認して特に問題ないとは思っていますが,正規表現にはあまり自信がないので間違いを見つけた方はどうかコメント欄等でご指摘ください。
なにをゆう たむらゆう。
おしまい。
注1: 記号類をそのまま使うときになんでもかんでもエスケープ記号つけるのは私の癖です(そして一貫性もないですたまに忘れるので)
注2: この方法の一つの問題は,”I ate lunch ,and took a nap.”のようなものが残ってしまうという点です。「半角スペースの直後にピリオドやカンマがあり,その直後に文字列が続く場合には,半角スペースを消して文字列とピリオドやカンマの後に挿入する」のようにすれば解決されます。ただし,関数の入れ子が複雑になる上に単語数カウントには関係ないので今回は無視しています。REGEXREPLACE関数でやるとすれば,次のようなものになるかなと思います。
= regexreplace ( 対象文字列のセル , “\s(\.|\,)(\w+)” , “$1 $2” )
注3: もしも,単語リストを作ったり,コロケーションを見たりのようにテキスト分析にいこうとすると,この絵文字タグは外してあげないと絵文字タグと隣接する文字列が認識されなくなってしまいます。
注4: 17:10:29のように時間をコロン区切りで書き込むような例があると,これも引っかかってしまうのですが,まあほとんどないと言っていいと思うので木にしていません。