Hashtable и проблема с заменой символов в массиве
Делаю переводчик в ситуации когда ты пишешь огромный текст на русском, а он на английском. Пример: "ghbdtn" - "привет" Всё работает отлично, но если текст вводить с цифрами или символами то они не отображаются в выводе. По нажатию кнопки происходит следующий код:
char[] translateChar = englishText.Text.ToCharArray();
Hashtable hashTbEngRus = new Hashtable
{
// Здесь хранится ключ в виде английских букв и значение в русских.
};
ICollection key = hashTbEngRus.Keys;
for (int i = 0; i < translateChar.Length; i++)
{
foreach (char lengthKey in key)
{
if (lengthKey == translateChar[i])
{
russianText.Text += englishText.Text.Replace(translateChar[i].ToString(), hashTbEngRus[lengthKey].ToString())[i];
break;
}
}
}
Я много вариантов проверил но никак не найду решение, проблема заключается в том, что цикл foreach проходится по всему ключу и если добавить
else russianText.Text += translateChar[i];
Оно будет выводить каждый элемент массива повторно пока не найдёт равный из-за чего в выводе получается полная фигня. Может не стоило работать тут с Hashtable или есть всё таки решение кроме того как добавить все символы, цифры и русские буквы.
Заранее спасибо за ответ.
Ответы (1 шт):
Используйте обобщённые коллекции, и зря весь код не показали.
string text = englishText.Text;
Dictionary<char, char> map = new()
{
['A'] = 'Ф',
// ...
};
StringBuilder sb = new(text.Length);
foreach (char c in text)
{
sb.Append(map.TryGetValue(c, out char x) ? x : c);
}
russianText.Text = sb.ToString();
Вот и всего делов.
Dictionary это то же самое что Hashtable только новее, быстрее и удобнее.
StringBuilder здесь используется для производительности и экономии памяти, он намного эффективнее, чем конкатенация строк. Используйте его если надо много клеить и резать строк, например как здесь. text.Length в конструкторе SB означает начальную ёмкость внутреннего хранилища билдера, указывать необязательно, но полезно, если заранее знаете, какой длины будет результат.
С тернарным оператором ?: надеюсь не возникнет сложности разобраться.
Если совсем сложно, то вот тело цикла попроще, делает то же самое.
if (map.ContainsKey(c))
sb.Append(map[c]);
else
sb.Append(c);
Разница только в том, что TryGetValue за один проход проверяет, есть ли ключ и сразу достаёт значение, если есть, а здесь сначала ищем, чтобы проверить, затем второй раз по индексатору, чтобы забрать символ. То есть в 2 раза медленнее этот код, но для коротких строк без разницы.