#include <bits/stdc++.h>
using namespace std;
const size_t kMaxReservedSize = 20;
struct Dict {
  void Add(const string &value) { m_values.push_back(value); }
  template <typename Value>
  bool Has(const Value &value) const {
    for (const auto &v : m_values) {
      if (value == v) return true;
    }
    return false;
  }
  vector<string> m_values;
};
bool IsNumberChar(int c) { return isdigit(c); }
bool IsWordChar(int c) { return isalnum(c) || c == '_' || c == '$'; }
bool IsReservedChar(int c) { return c >= 33 && c <= 126 && c != 35; }
struct StringView {
  StringView() = default;
  StringView(const string &s) : m_buf(s.data()), m_size(s.size()) {}
  StringView(const char *buf, size_t size) : m_buf(buf), m_size(size) {}
  bool StartsWith(const StringView &prefix) const {
    if (prefix.size() > size()) return false;
    return equal(cbegin(), cbegin() + prefix.size(), prefix.cbegin());
  }
  size_t size() const { return m_size; }
  bool empty() const { return m_size == 0; }
  char operator[](size_t i) const {
    assert(i < m_size);
    return m_buf[i];
  }
  string ToString() const { return {m_buf, m_size}; }
  StringView SubStr(size_t from, size_t size) const {
    assert(from + size <= m_size);
    return StringView{m_buf + from, size};
  }
  const char *begin() const { return m_buf; }
  const char *cbegin() const { return m_buf; }
  const char *end() const { return m_buf + m_size; }
  const char *cend() const { return m_buf + m_size; }
  const char *m_buf = nullptr;
  size_t m_size = 0;
};
bool operator==(const StringView &lhs, const StringView &rhs) {
  if (lhs.size() != rhs.size()) return false;
  return equal(lhs.cbegin(), lhs.cend(), rhs.cbegin());
}
bool operator!=(const StringView &lhs, const StringView &rhs) {
  return !(lhs == rhs);
}
ostream &operator<<(ostream &os, const StringView &s) {
  copy(s.cbegin(), s.cend(), ostreambuf_iterator<char>(os));
  return os;
}
enum class Type { Word, Number, Reserved };
template <typename Value>
struct Token {
  Token() = default;
  Token(const Value &value, Type type) : m_value(value), m_type(type) {}
  Value m_value;
  Type m_type = Type::Word;
};
bool IsReserved(const StringView &token, const Dict &dict) {
  if (token.size() > kMaxReservedSize) return false;
  return dict.Has(token);
}
bool IsNumber(const StringView &token) {
  assert(!token.empty());
  for (const auto &c : token) {
    if (!isdigit(c)) return false;
  }
  return true;
}
bool IsWord(const StringView &token) {
  assert(!token.empty());
  if (isdigit(token[0])) return false;
  for (const auto &c : token) {
    if (!isalnum(c) && c != '_' && c != '$') return false;
  }
  return true;
}
template <bool HasSpaces>
struct Tokenizer {
  Tokenizer(const StringView &line, const Dict &dict)
      : m_line(line), m_dict(dict) {
    EatSpaces();
  }
  void EatSpaces() {
    if (!HasSpaces) return;
    while (m_pos < m_line.size() && isspace(m_line[m_pos])) ++m_pos;
  }
  bool HasNextToken() const { return m_pos < m_line.size(); }
  template <typename String>
  bool IsNextToken(const Token<String> &token) const {
    assert(!token.m_value.empty());
    const StringView curr = m_line.SubStr(m_pos, m_line.size() - m_pos);
    if (!curr.StartsWith(token.m_value)) return false;
    size_t pos = m_pos + token.m_value.size();
    if (pos == m_line.size()) return true;
    StringView reserved = EatLongestReserved();
    if (!reserved.empty() && reserved.size() > token.m_value.size())
      return false;
    assert(pos < m_line.size());
    switch (token.m_type) {
      case Type::Number:
        return !IsNumberChar(m_line[pos]);
      case Type::Word:
        return !IsWordChar(m_line[pos]);
      case Type::Reserved:
        if (token.m_value != reserved) return false;
        if (IsWord(token.m_value) && IsWordChar(m_line[pos])) return false;
        if (IsNumber(token.m_value) && IsNumberChar(m_line[pos])) return false;
        return true;
    }
    assert(false);
    return false;
  }
  Token<StringView> NextToken() {
    assert(HasNextToken());
    Token<StringView> best;
    {
      const StringView curr = EatLongestReserved();
      if (curr.size() > best.m_value.size())
        best = Token<StringView>{curr, Type::Reserved};
    }
    {
      const StringView curr = EatLongestNumber();
      if (curr.size() > best.m_value.size())
        best = Token<StringView>{curr, Type::Number};
    }
    {
      const StringView curr = EatLongestWord();
      if (curr.size() > best.m_value.size())
        best = Token<StringView>{curr, Type::Word};
    }
    assert(!best.m_value.empty());
    m_pos += best.m_value.size();
    EatSpaces();
    return best;
  }
  StringView EatLongestNumber() const {
    assert(HasNextToken());
    size_t pos = m_pos;
    for (; pos < m_line.size() && IsNumberChar(m_line[pos]); ++pos)
      ;
    return m_line.SubStr(m_pos, pos - m_pos);
  }
  StringView EatLongestWord() const {
    assert(HasNextToken());
    size_t pos = m_pos;
    for (; pos < m_line.size() && IsWordChar(m_line[pos]); ++pos)
      ;
    if (pos != m_pos && IsNumberChar(m_line[m_pos])) return {};
    return m_line.SubStr(m_pos, pos - m_pos);
  }
  StringView EatLongestReserved() const {
    assert(HasNextToken());
    StringView best;
    for (size_t pos = m_pos; pos < m_line.size() && IsReservedChar(m_line[pos]);
         ++pos) {
      auto curr = m_line.SubStr(m_pos, pos - m_pos + 1);
      if (curr.size() > kMaxReservedSize) break;
      if (IsReserved(curr, m_dict)) best = curr;
    }
    return best;
  }
  StringView m_line;
  size_t m_pos = 0;
  const Dict &m_dict;
};
struct Generator {
  explicit Generator(const Dict &dict) : m_dict(dict), m_curr("a") {
    while (m_dict.Has(m_curr)) Next();
  }
  string Gen() {
    assert(!m_dict.Has(m_curr));
    const string result = m_curr;
    do Next();
    while (m_dict.Has(m_curr));
    return result;
  }
  void Next() {
    assert(!m_curr.empty());
    size_t i = m_curr.size() - 1;
    for (; i < m_curr.size() && m_curr[i] == 'z'; --i) m_curr[i] = 'a';
    if (i < m_curr.size())
      ++m_curr[i];
    else
      m_curr.insert(m_curr.begin(), 'a');
  }
  const Dict &m_dict;
  string m_curr;
};
void RemoveComment(string &line) {
  const auto pos = line.find('#');
  if (pos != string::npos) line.erase(pos);
}
int main() {
  size_t numReserved;
  cin >> numReserved;
  Dict dict;
  for (size_t i = 0; i < numReserved; ++i) {
    string reserved;
    cin >> reserved;
    dict.Add(reserved);
  }
  size_t numLines;
  cin >> numLines;
  string line;
  getline(cin, line);
  vector<Token<string>> tokens;
  for (size_t lineNum = 0; lineNum < numLines; ++lineNum) {
    getline(cin, line);
    RemoveComment(line);
    Tokenizer<true> tokenizer(line, dict);
    while (tokenizer.HasNextToken()) {
      const auto token = tokenizer.NextToken();
      tokens.emplace_back(token.m_value.ToString(), token.m_type);
    }
  }
  Generator generator(dict);
  unordered_map<string, string> translation;
  for (auto &token : tokens) {
    switch (token.m_type) {
      case Type::Number:
      case Type::Reserved:
        break;
      case Type::Word: {
        const auto it = translation.find(token.m_value);
        if (it != translation.end()) {
          token.m_value = it->second;
        } else {
          const string tr = generator.Gen();
          translation[token.m_value] = tr;
          token.m_value = tr;
        }
        break;
      }
    }
  }
  string allTokens;
  for (const auto &token : tokens) allTokens.append(token.m_value);
  vector<vector<size_t>> totalLen(tokens.size());
  vector<vector<bool>> valid(tokens.size());
  for (size_t i = 0; i < tokens.size(); ++i) {
    size_t total = 0;
    for (size_t len = 0; i + len <= tokens.size(); ++len) {
      valid[i].push_back(false);
      totalLen[i].push_back(total);
      if (i + len < tokens.size()) total += tokens[i + len].m_value.size();
    }
    assert(valid[i].size() >= 2);
  }
  for (size_t i = 0; i < tokens.size(); ++i) {
    valid[i][0] = false;
    valid[i][1] = true;
  }
  for (size_t len = 2; len <= tokens.size(); ++len) {
    for (size_t i = 0; i + len <= tokens.size(); ++i) {
      if (!valid[i + 1][len - 1]) continue;
      Tokenizer<false> tokenizer{
          StringView{allTokens.data() + totalLen[0][i], totalLen[i][len]},
          dict};
      valid[i][len] = tokenizer.IsNextToken(tokens[i]);
    }
  }
  vector<size_t> minSize(tokens.size() + 1);
  vector<size_t> nextTok(tokens.size() + 1);
  for (size_t i = tokens.size() - 1; i < tokens.size(); --i) {
    size_t currSize = tokens[i].m_value.size();
    minSize[i] = currSize + (i + 1 == tokens.size() ? 0 : minSize[i + 1] + 1);
    nextTok[i] = i + 1;
    for (size_t j = i + 1; j < tokens.size(); ++j) {
      if (!valid[i][j - i + 1]) break;
      currSize += tokens[j].m_value.size();
      const size_t size =
          currSize + (j + 1 == tokens.size() ? 0 : minSize[j + 1] + 1);
      if (size < minSize[i]) {
        minSize[i] = size;
        nextTok[i] = j + 1;
      }
    }
  }
  size_t curr = 0;
  while (curr < tokens.size()) {
    for (size_t i = curr; i < nextTok[curr]; ++i) cout << tokens[i].m_value;
    curr = nextTok[curr];
    if (curr != tokens.size()) cout << " ";
  }
  cout << endl;
  return 0;
}
