#include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


struct Info{

	int h,w;
	char ch,rev_ch;
	char table[15][16],rev_table[15][16];
};

struct Data{

	string str;
	bool is_rev;
};

struct State{
	State(){
		row = col = 0;
	}

	State(int arg_row,int arg_col){
		row = arg_row;
		col = arg_col;
	}
	int row,col;
};

int num_glyph,num_monolith;
int max_glyph_H;
int index_table[26];
Info info[26];
char base_map[105][1010];

Data calc_term(int,int,int,int);
string calc_seq(int,int,int,int);
string calc_box(int,int,int,int);


bool is_Same(char A[15][16],char B[15][16],int H,int W){

	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){
			if(A[row][col] != B[row][col]){

				return false;
			}
		}
	}

	return true;
}

//最大のグリフより高いならBOX
bool is_BOX(int row,int col){

	int tmp_H = 1;

	while(base_map[row+1][col] == '*'){

		row++;
		tmp_H++;
	}

	return tmp_H > max_glyph_H;
}


Data calc_term(int row1,int col1,int row2,int col2){

	Data ret;
	ret.str = "";
	ret.is_rev = false;


	char work[15][16];

	for(int row = row1; row <= row2; row++){
		for(int col = col1; col <= col2; col++){

			work[row-row1][col-col1] = base_map[row][col];
		}
	}

	int H = row2-row1+1,W = col2-col1+1;

	bool FLG = false;

	//★★先に、ノーマル全部を探す★★
	for(int i = 0; i < num_glyph; i++){

		if(info[i].h != H || info[i].w != W)continue;

		if(is_Same(work,info[i].table,H,W)){
			FLG = true;
			ret.str = info[i].ch;
			break;
		}
	}

	if(!FLG){

		for(int i = 0; i < num_glyph; i++){


			if(info[i].h != H || info[i].w != W)continue;

			if(is_Same(work,info[i].rev_table,H,W)){

				ret.str = info[i].ch;
				ret.is_rev = true;
				break;
			}
		}
	}

	return ret;
}

string calc_seq(int row1,int col1,int row2,int col2){

	string ret = "";
	bool rev_FLG = false;
	vector<string> V;

	for(int row = row1,col = col1; col <= col2; ){

		if(base_map[row][col] == '*'){ //BOX or term発見

			if(is_BOX(row,col)){

				int tmp_row,tmp_col;

				for(tmp_col = col; tmp_col+1 <= col2 && base_map[row][tmp_col+1] == '*'; tmp_col++);
				for(tmp_row = row; tmp_row+1 <= row2 && base_map[tmp_row+1][col] == '*'; tmp_row++);

				V.push_back(calc_box(row,col,tmp_row,tmp_col));

				row = row1;
				col = tmp_col+1;

			}else{

				//上下左右の座標を求める
				int top = row,under = row,left = col,right = col;
				bool black_FLG;

				int tmp_row,tmp_col;

				for(tmp_row = row+1; tmp_row <= row2; tmp_row++){
					if(base_map[tmp_row][col] == '*'){
						under = tmp_row;
					}
				}

				for(tmp_col = col+1; tmp_col <= col2; tmp_col++){
					black_FLG = false;
					for(tmp_row = row1; tmp_row <= row2;tmp_row++){
						if(base_map[tmp_row][tmp_col] == '*'){
							top = min(top,tmp_row);
							under = max(under,tmp_row);
							right = tmp_col;
							black_FLG = true;
						}

					}
					if(!black_FLG)break;
				}

				Data term = calc_term(top,left,under,right);

				V.push_back(term.str);
				rev_FLG |= term.is_rev;

				col = right+1;
				row = row1;
			}

		}else{

			row++;
			if(row > row2){
				row = row1;
				col++;
			}
		}
	}

	if(rev_FLG){

		reverse(V.begin(),V.end());
		for(int i = 0; i < V.size(); i++){
			if(V[i].length() >= 2)continue; //箱はカッコが必ずついている

			int tmp_index = index_table[V[i][0]-'a'];
			char rev_ch = info[tmp_index].rev_ch;
			if(rev_ch == '@')continue;

			V[i][0] = rev_ch; //元の文字に戻す
		}
	}

	for(int i = 0; i < V.size(); i++){

		ret += V[i];
	}

	return ret;
}

string calc_box(int row1,int col1,int row2,int col2){

	string ret = calc_seq(row1+1,col1+1,row2-1,col2-1);
	ret = "[" + ret + "]";

	return ret;
}


void func(){

	char buf[2];

	max_glyph_H = 0; //★★ボックスかどうか判定するのに、最大のグリフの高さが必要★★

	for(int i = 0; i < num_glyph; i++){

		scanf("%s %d %d",buf,&info[i].h,&info[i].w);
		info[i].ch = buf[0];

		index_table[info[i].ch-'a'] = i; //文字からインデックスの逆引き表

		max_glyph_H = max(max_glyph_H,info[i].h);

		for(int row = 0; row < info[i].h; row++){

			scanf("%s",info[i].table[row]);
		}
		//左右反転したグリフを作る
		for(int col = 0; col < info[i].w; col++){
			for(int row = 0; row < info[i].h; row++){

				info[i].rev_table[row][col] = info[i].table[row][info[i].w-1-col];
			}
		}
	}


	//★★反転関係を調べる★★
	for(int i = 0; i < num_glyph; i++){

		char rev_ch = '@';

		for(int k = 0; k < num_glyph; k++){
			if(info[i].h != info[k].h || info[i].w != info[k].w)continue;

			if(is_Same(info[i].rev_table,info[k].table,info[i].h,info[i].w)){

				rev_ch = info[k].ch;
				break;
			}
		}

		info[i].rev_ch = rev_ch;
	}

	char work_map[1010];

	for(int loop = 0; loop < num_monolith; loop++){

		int H,W;
		scanf("%d %d",&H,&W);

		//ダミーセルで覆う
		for(int row = 0; row <= H+1; row++){
			base_map[row][0] = '.';
			base_map[row][W+1] = '.';
		}

		for(int col = 0; col <= W+1; col++){
			base_map[0][col] = '.';
			base_map[H+1][col] = '.';
		}

		for(int row = 1; row <= H; row++){

			scanf("%s",work_map);
			for(int col = 0;col < W; col++){
				base_map[row][col+1] = work_map[col];
			}
		}

		string ans;

		ans = calc_seq(0,0,H+1,W+1);

		printf("%s\n",ans.c_str());
	}
	printf("#\n");
}

int main(){

	while(true){

		scanf("%d %d",&num_glyph,&num_monolith);
		if(num_glyph == 0 && num_monolith == 0)break;

		func();
	}

	return 0;
}



Measured memory_bytes: 3384