IQ Botでは、処理するOCRエンジンを自由に選択することができます。
選択可能なOCRエンジンの特徴やクセをこちらの記事にまとめていますが、エンジンによっては、「YYYY/MM/DD」形式の日付の「/」(スラッシュ)を「1」と読んでしまうケースが見られました。
例:2020/11/11と書いてあるのを、2020111111と読んでしまう 等
もちろん、このような場合は日付(date)型を指定しておくことで誤り検知をするのが一般的な対応ですが、カスタムロジックを使ってある程度正しい形に補正してから誤り検知をかけた方が効率的です。
そんなわけで、標記の問題に対して筆者が作成したカスタムロジックを公開してみます。
いろいろ場合分けしていたらけっこうな行数になってしまいました。
もっとシンプルなやり方を思いついた方はぜひコメントください。
日付のスラッシュを1と読んでしまった場合に使えるカスタムロジック
1と読まれてしまった日付のスラッシュをスラッシュに戻す
# スラッシュが入るべき位置に1があった場合、その文字をスラッシュに置き換える関数
def slashConvert(x,index):
if x[index] == "1":
x = x[:index] + "/" + x[index + 1:]
return x
# スラッシュが入るべき位置を特定し、かつ変換をかける関数
# x = もとの値、y = 年の桁数(YYYY/MM/DDなら4,YY/MM/DDなら2)を渡す
def date1toSlash(x,y):
# すでにスラッシュが2つ以上含まれていたらそのままreturn
if "/" in x:
if len(x.split("/")) >= 3:
return x
# 年の数字以降は最低/M/Dで4文字以上あるはず
# それに満たなければそのままreturn (=検証で検知)
if len(x) < y + 4:
return x
# 年と月の間にスラッシュを入れる
x = slashConvert(x,y)
# 月と日の間にスラッシュを入れるために、どの桁にスラッシュが入るかを求める
# 不明の場合はそのままreturn → すると日付として不完全な値が返るので、IQ Bot側の検証で検知できるという仕組み
if len(x) == y + 6: # 年以外が6桁 = /MM/DD = 月日ともに2桁 = おしりから3桁目がスラッシュ
mdIndex = -3
elif len(x) == y + 5: # 年以外が5桁 = /M/DD or /MM/D ← いずれかを見極める必要あり
if 2 <= int(x[y+1]) <= 9: # 年の次の桁が2~9なら、2月~9月=1桁月なので、M/DD = おしりから3桁目がスラッシュ
mdIndex = -3
elif x[y+1] == "0": # 年の次の桁がゼロ = MM/D? でも月だけゼロ埋めしてあるのは怪しいのでそのままreturn
return x
elif x[-3:-1] == "11": # おしりから3桁目&おしりから2桁目の並びが「11」(つまり最後の4桁が?11?)の場合
if x[-4:] == "1110": # 1110なら1/10に決まりだが……
mdIndex = -3
else: # 上記以外(1111など)は1/11なのか11/1なのか判断できないのでそのままreturn
return x
elif (x[-3] == "1") and (x[-2] != "1"): #月日部分が1120なら1/20に決まる
mdIndex = -3
elif (x[-2] == "1") and (x[-3] != "1"): #月日部分が1211なら12/1に決まる
mdIndex = -2
else: # 上記以外のパターンは想定なし
return x
else: # else に来るのは年以外が4桁のパターン = /M/Dなのでおしりから2桁目がスラッシュ
mdIndex = -2
x = slashConvert(x,mdIndex)
return x
#フィールド項目に対して適用する場合で、年の桁数が4桁の場合
field_value = date1toSlash(field_value,4)
#テーブル項目に対して適用する場合で、年の桁数が2桁の場合
df['列名'] = df['列名'].apply(date1toSlash,y=2)
上記のテーブルに対して適用する場合のコードは、おまじないコードの間にはさんでいる前提です。