採用面接の実技課題の問題でボツになった案
こんにちは、高木です。
9月から実務未経験者を含む技術職の採用面接を行っています。
面接の中で実技課題をやってもらっているのですが、その問題を作るのがこれまた難しいのです。
あまり応募者をバカにしたような簡単すぎる問題を出すのもどうかと思いますし、かといって難しい問題を出して自信を喪失させるのも気の毒です。
いろいろ検討を重ねる中でボツになった課題のひとつを今回は紹介することにしましょう。
問題
引数で指定した文字列に含まれる文字数を返す関数lengthを作成しなさい。
条件
1. 標準Cで書くこと
2. 日本語を扱えるようにすること
3. 不明点は質問すること
この問題の難度を跳ね上げているのが2.の条件です。
2.の条件がなければ、すなわち基本実行文字集合だけを扱うのであれば、話は簡単です。
1 2 3 4 5 | #include <string.h> size_t length(const char *s) { return strlen(s); } |
でもかまいませんし、
1 2 3 4 5 6 7 8 | #include <stddef.h> size_t length(const char *s) { const char *ss; for (ss = s; *ss != '\0'; ss++) ; return ss - s; } |
のように、スクラッチで書いてもOKです。
問題はやはり2.の条件にある「日本語を扱えること」にあります。
そして、この条件がある場合にさらに難度を上げているのが、1.の条件である「標準Cで書くこと」なのです。
標準Cにこだわらなければ、特定の処理系でしか使えない便利な関数を使える可能性も出てきます。
その可能性を最初につぶしているのが1.の条件なのです。
課題をクリアするだけであれば、一番安直な方法は次のような回答かと思います。
1 2 3 4 5 6 7 8 | #include <uchar.h> size_t length(const char32_t *s) { const char32_t *ss; for (ss = s; *ss != U'\0'; ss++) ; return ss - s; } |
これであれば、UCS-4の文字列を対象としていますので、日本語を扱えるとみなしていいでしょう。
ただ、この関数の実用価値はそれほど高くありません(まったくの無価値ではありませんが)。
そもそもC11に対応したコンパイラが使えない状況は多いですし、コンパイラが対応していてもプロジェクトの方針でC11を使わないことはもっと多いはずです。
第一、文字列にchar32_tを使うことは、かなりまれではないでしょうか?
その意味で、実用価値は高くないのです。
では、ワイド文字列を使うのならどうでしょうか?
1 2 3 4 5 | #include <wchar.h> size_t length(const wchar_t *s) { return wcslen(s); } |
または
1 2 3 4 5 6 7 8 | #include <stddef.h> size_t length(const wchar_t *s) { const wchar_t *ss; for (ss = s; *ss != L'\0'; ss++) ; return ss - s; } |
とするのです。
特定の環境であれば、これでも問題ないと思います。
しかし、ワイド文字で日本語の1文字を本当に扱えるかどうかは処理系定義です。
Visual C++なら大丈夫と考える人もいるかもしれませんが、そんなに甘くはありません。
wchar_tにUnicodeを格納できたとしてもサロゲートペアまで正しく処理しなければ、日本語文字列に含まれる文字数を数えることはできないのです。
それに、wchar_t自体が処理系定義で、char型と同じ表現範囲しかない処理系も存在するのです。
では、mblenを使って次のようにすればどうでしょうか?
1 2 3 4 5 6 7 8 9 10 11 12 | #include <stdlib.h> size_t length(const char *s) { size_t r = 0; int n; while ((n = mblen(s, MB_CUR_MAX)) > 0) { ++r; s += n; } return r; } |
私は最初、この辺りが現実的な落としどころではないかと考えていました。
しかし、mblen(s, n)はmbtowc(NULL, s, n)と等価ですので、wchar_t型で1文字を表現できないのであれば、やはりこの方法でも正しく文字数を数えられないのです。
(それに、実技課題で期待する回答としては難度が高すぎます)
C11を使えるのであれば、mblenの代わりにmbrtoc32を使うという手もありますが、どんどん現実離れしていってしまいますね。
というわけで、この案はボツになりました。