116  練習問題

library(tidyverse)

お疲れ様です、とりあえず、ここまでで基本的な事項は解説が終わりました。

智識の定着をはかるため、練習問題を解いておきましょう

Q1 次の文章を正規表現で書き表してください。

0から5までの数字3文字に続いて0から9までの数字3から5文字

dogの3文字ではじまって、wanwanwanで終わる文字列。(dogとwanwanwanの間の文字はなんでもよくて、その長さは1文字以上10文字以下)

310から329までの整数に該当する文字列

Q2 次のベクトルの中に含まれる検査結果を抜き出してください

vec <- c("1HbA1c :4.9", "2HbA1c: 6.3", "3HbA1c : 3", "4HbA1c:5")

Q3 次のデータにはすべて数字のはずですが、誤入力によりアルファベットが紛れ込んでいるデータがあります。それを発見してください。

vec <- c("100000", "|o000", "l820", "201q", "1234s")

それでは答えです。

Q1 次の文章を正規表現で書き表してください。

0から5までの数字3文字に続いて0から9までの数字3から5文字

reg_q11 <- "[0-5]{3}[0-9]{3,5}"

tgt_q11 <- c("123999","456999","1239999","12399999","1239")

str_view(tgt_q11, reg_q11)
[1] │ <123999>
[3] │ <1239999>
[4] │ <12399999>

dogの3文字ではじまって、wanwanwanで終わる文字列。(dogとwanwanwanの間の文字はなんでもよくて、その長さは1文字以上10文字以下)

reg_q12 <- "dog.{1,10}wanwanwan$"
tgt_q12 <- c(
  "dog123456789awanwanwan",
  "dog123456wanwanwan",
  "dogwanwanwanwanwan",
  "dogwanwanwan",
  "dog123456789abwanwanwan",
  "dog1234wanwan"
)

str_view(tgt_q12, reg_q12)
[1] │ <dog123456789awanwanwan>
[2] │ <dog123456wanwanwan>
[3] │ <dogwanwanwanwanwan>

310から329までの整数に該当する文字列

reg_q13 <- "3[1-2][0-9]"
tgt_q13_1 <- as.character(300:320)
tgt_q13_2 <- as.character(321:340)

str_view(tgt_q13_1,reg_q13)
[11] │ <310>
[12] │ <311>
[13] │ <312>
[14] │ <313>
[15] │ <314>
[16] │ <315>
[17] │ <316>
[18] │ <317>
[19] │ <318>
[20] │ <319>
[21] │ <320>
str_view(tgt_q13_2,reg_q13)
[1] │ <321>
[2] │ <322>
[3] │ <323>
[4] │ <324>
[5] │ <325>
[6] │ <326>
[7] │ <327>
[8] │ <328>
[9] │ <329>

できましたか?

Q2 次のベクトルの中に含まれる検査結果を抜き出してください

vec <- c("1HbA1c :4.9", "2HbA1c: 6.3", "3HbA1c : 3", "4HbA1c:5")

出題しておいて難ですが、これは結構ややこしいです。まずは、コロンの右側にある数字を指定してあげないと、コロンの左側の数字が引っかかってきます。

なので、

"(?<=:)"
[1] "(?<=:)"

です。ここで、小数と整数両方ひっかける正規表現をそのまま書くと、

"(?<=)\\d+\\.\\d+|\\d+"
[1] "(?<=)\\d+\\.\\d+|\\d+"
str_view(vec,"(?<=)\\d+\\.\\d+|\\d+")
[1] │ <1>HbA<1>c :<4.9>
[2] │ <2>HbA<1>c: <6.3>
[3] │ <3>HbA<1>c : <3>
[4] │ <4>HbA<1>c:<5>

うまくいきません。なぜかというと、

(?<=)\d+\.\d+|\d+” (?<=)\d+\.\d+|\d+” |—————|—|

という風に、コロンの後ろの小数 あるいは 整数という正規表現になっているからです。

これをただすためには、

(?<=)(\d+\.\d+|\d+)” |———–|—-| |———————|

という具合で、コロンの後ろを表す正規表現の後ろに()をつけて、小数か整数を指定してあげないといけません

str_view(vec,"(?<=:)((\\d+\\.\\d+)|\\d+)")
[1] │ 1HbA1c :<4.9>
[4] │ 4HbA1c:<5>

ただ、これだけでも実は不十分で、コロンの後ろにスペースがある場合は正規表現がうまく働きません。ややこしいので、全パターン書き出してみましょう。ここでスペースは。

1 (?<=:) \d+\.\d+ 2 (?<=:\s)\d+\.\d+ 3 (?<=:\s)\d+ 4 (?<=:) \d+

パターンを組み合わせると 1&4 (?<=:)(\d+\.\d+|\d+) 2&3 (?<=:\s)(\d+\.\d+|\d+)

こうなります。

Look Aroundの部分は、

(?<=:(\s|)) -(—| -( |)

と、コロンに続いてスペース あるいは コロンに続いて何もなしと記載できるので、それに、小数あるいは整数を組み合わせると、

str_view(vec,"(?<=:(\\s|))(\\d+\\.\\d+|\\d+)")
[1] │ 1HbA1c :<4.9>
[2] │ 2HbA1c: <6.3>
[3] │ 3HbA1c : <3>
[4] │ 4HbA1c:<5>

となります。

こういう出力、結構汚いデータではよくあるので、正規表現で抽出できるとよいかもしれません。

ただし、実は

tibble(test = vec) %>% 
  separate(test,into=c("kensa","value"), sep=":") %>% 
  mutate(value2 = str_trim(value,"both"))
# A tibble: 4 × 3
  kensa     value  value2
  <chr>     <chr>  <chr> 
1 "1HbA1c " "4.9"  4.9   
2 "2HbA1c"  " 6.3" 6.3   
3 "3HbA1c " " 3"   3     
4 "4HbA1c"  "5"    5     

後の方でお伝えする関数を併用すればすごく簡単に正規表現で頭を悩ませる必要なく処理できたりするので、正規表現ごりごりいける人以外はtidyverseで用意されている関数群を利用することを推奨いたします。

Q3 次のデータにはすべて数字のはずですが、誤入力によりアルファベットが紛れ込んでいるデータがあります。それを発見してください。

vec <- c("100000", "|o000", "l820", "201q", "1234s")

これは色々とやり方ありますが、

str_view(vec,"\\D+")
[2] │ <|o>000
[3] │ <l>820
[4] │ 201<q>
[5] │ 1234<s>

で数字以外を見つけるようなやり方が手っ取り早いかもしれません

以上、正規表現の解説と練習問題でした。

slide69にある内容、もう一度見返してみましょう。最初に暗号の様に見えていたと思いますが、今だったらそれほど難しい正規表現ではないとご理解いただけますね?

おつかれさまでした。

本コースの難所の一つである正規表現の説明はこれでおしまいです。

次からはこの正規表現を活用してデータをキレイにする作業方法について解説していきます。