Problem:
Problem A: Keitai Message

Alice さんは Miku さんに携帯電話でメールを送ろうとしている。

携帯電話には入力に使えるボタンは数字のボタンしかない。 そこで、文字の入力をするために数字ボタンを何度か押して文字の入力を行う。携帯電話の数字ボタンには、次の文字が割り当てられており、ボタン 0 は確定ボタンが割り当てられている。この携帯電話では 1 文字の入力が終わったら必ず確定ボタンを押すことになっている。

1: . , ! ? (スペース)

2: a b c

3: d e f

4: g h i

5: j k l

6: m n o

7: p q r s

8: t u v

9: w x y z

0: 確定ボタン

例えば、ボタン 2、ボタン 2、ボタン 0 と押すと、文字が 'a' → 'b' と変化し、ここで確定ボタンが押されるので、文字 b が出力される。
同じ数字を続けて入力すると変化する文字はループする。すなわち、ボタン 2 を 5 回押して、次にボタン 0 を押すと、文字が 'a' → 'b' → 'c' → 'a' → 'b' と変化し、ここで確定ボタンを押されるから 'b' が出力される。

何もボタンが押されていないときに確定ボタンを押すことはできるが、その場合には何も文字は出力されない。

あなたの仕事は、Alice さんが押したボタンの列から、Alice さんが作ったメッセージを再現することである。

Input

最初の行にテストケースの数が与えられる。 続いて各テストケースについて、最大で長さ 1024 の数字列が1行で与えられる。

Output

Alice さんが作ったメッセージの文字列をそれぞれのテストケースについて 1 行ごとに出力せよ。
ただし、出力は 1 文字以上 76 文字未満であると仮定してよい。

Sample Input

5
20
220
222220
44033055505550666011011111090666077705550301110
000555555550000330000444000080000200004440000

Output for the Sample Input

a
b
b
hello, world!
keitai

Solution in C# (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace _2006
{
    public class Program

    {
        public static void Main(string[] args)
        {
            int n = ReadInt();

            string[] b0 = new string[] { "" };
            string[] b1 = new string[] { ".", ",", "!", "?", " " };
            string[] b2 = new string[] { "a", "b", "c" };
            string[] b3 = new string[] { "d", "e", "f" };
            string[] b4 = new string[] { "g", "h", "i" };
            string[] b5 = new string[] { "j", "k", "l" };
            string[] b6 = new string[] { "m", "n", "o" };
            string[] b7 = new string[] { "p", "q", "r", "s" };
            string[] b8 = new string[] { "t", "u", "v" };
            string[] b9 = new string[] { "w", "x", "y", "z" };
            string[][] buttons = new string[][] { b0, b1, b2, b3, b4, b5, b6, b7, b8, b9 };

            for (int i = 0 ; i < n ; i++)
            {
                string line = ReadSt();
                char num = 'x';
                int pushCnt = 0;
                string res = "";

                for (int j = 0 ; j < line.Length ; j++)
                {
                    if (line[j] == '0' && pushCnt > 0)
                    {
                        res += buttons[int.Parse(num.ToString())][(pushCnt - 1) % buttons[int.Parse(num.ToString())].Length];
                        pushCnt = 0;
                    }
                    else if (line[j] != '0' && line[j] == num)
                    {
                        pushCnt++;
                    }
                    else if (line[j] != '0' && line[j] != num)
                    {
                        num = line[j];
                        pushCnt = 1;
                    }
                }
                Console.WriteLine(res);
            }

        }

        static string ReadSt() { return Console.ReadLine(); }
        static int ReadInt() { return int.Parse(Console.ReadLine()); }
        static long ReadLong() { return long.Parse(Console.ReadLine()); }
        static double ReadDouble() { return double.Parse(Console.ReadLine()); }
        static string[] ReadStAr(char sep = ' ') { return Console.ReadLine().Split(sep); }
        static int[] ReadIntAr(char sep = ' ') { return Array.ConvertAll(Console.ReadLine().Split(sep), e => int.Parse(e)); }
        static long[] ReadLongAr(char sep = ' ') { return Array.ConvertAll(Console.ReadLine().Split(sep), e => long.Parse(e)); }
        static double[] ReadDoubleAr(char sep = ' ') { return Array.ConvertAll(Console.ReadLine().Split(sep), e => double.Parse(e)); }
        static string WriteAr(int[] array, string sep = " ") { return String.Join(sep, array.Select(x => x.ToString()).ToArray()); }
        static string WriteAr(double[] array, string sep = " ") { return String.Join(sep, array.Select(x => x.ToString()).ToArray()); }
        static string WriteAr(long[] array, string sep = " ") { return String.Join(sep, array.Select(x => x.ToString()).ToArray()); }

    }

}