Как сделать следующий шаг строки. С#
вопрос сложный, но я объясню это в деталях.
цель состоит в том, чтобы сделать функцию, которая будет возвращать следующий "шаг" данной строки.
String.Step("a"); // = "b"
String.Step("b"); // = "c"
String.Step("g"); // = "h"
String.Step("z"); // = "A"
String.Step("A"); // = "B"
String.Step("B"); // = "C"
String.Step("G"); // = "H"
пока здесь это довольно легко, но, учитывая, что вход является строкой, он может содержать более 1 символов, и функция должна вести себя так.
String.Step("Z"); // = "aa";
String.Step("aa"); // = "ab";
String.Step("ag"); // = "ah";
String.Step("az"); // = "aA";
String.Step("aA"); // = "aB";
String.Step("aZ"); // = "ba";
String.Step("ZZ"); // = "aaa";
и так далее...
Это точно не нужно расширять базовую строку класс.
Я попытался разобраться с каждым значением ASCII символов, но застрял со строками, содержащими 2 символа.
Я был бы очень признателен, если кто-то может предоставить полный код функции.
спасибо заранее.
редактировать *Мне жаль, что я забыл упомянуть ранее, что функция "повторной обработки" самостоятельно созданную строку, когда ее длина достигает n.
continuation of this function will be smth like this. for example n = 3
String.Step("aaa"); // = "aab";
String.Step("aaZ"); // = "aba";
String.Step("aba"); // = "abb";
String.Step("abb"); // = "abc";
String.Step("abZ"); // = "aca";
.....
String.Step("zzZ"); // = "zAa";
String.Step("zAa"); // = "zAb";
........
прости, что не упомянул об этом. ранее, прочитав некоторые ответы, я понял, что проблема была под вопросом.
без этого функция всегда будет производить символ "a"n раз после окончания этапа.
10 ответов
Примечание: ответ неправильно, поскольку " aa "должно следовать за"Z"... (см. комментарии ниже)
вот алгоритм, который может сработать:
каждая "строка" представляет собой число для заданной базы (здесь: дважды количество букв в алфавите).
следующий шаг, таким образом, может быть вычислен путем разбора строки"number" обратно в int, добавления 1, а затем форматирования ее обратно в основа.
пример:
"a" == 1 -> step("a") == step(1) == 1 + 1 == 2 == "b"
теперь ваша проблема сводится к разбору строки как числа на заданную базу и ее переформатированию. Быстро погуглив можно предположить, что это страницы: http://everything2.com/title/convert+любой+номер+для+десятичное
Как это реализовать?
- таблица подстановки букв к их соответствующему номеру: a=1, b=2, c=3,... Y = ?, Z = 0
- чтобы разобрать строку на число, прочитайте символы в обратном порядке, просматривая цифры и складывая их:
- "ab" - > 2 * BASE^0 + 1 * BASE^1
- С базой, являющейся числом "цифр" (2 количество букв в алфавите, это 48?)
EDIT: эта ссылка выглядит еще более многообещающей:http://www.citidel.org/bitstream/10117/20/12/convexp.html
довольно коллекция подходов, вот моя: -
Функции:
private static string IncrementString(string s)
{
byte[] vals = System.Text.Encoding.ASCII.GetBytes(s);
for (var i = vals.Length - 1; i >= 0; i--)
{
if (vals[i] < 90)
{
vals[i] += 1;
break;
}
if (vals[i] == 90)
{
if (i != 0)
{
vals[i] = 97;
continue;
}
else
{
return new String('a', vals.Length + 1);
}
}
if (vals[i] < 122)
{
vals[i] += 1;
break;
}
vals[i] = 65;
break;
}
return System.Text.Encoding.ASCII.GetString(vals);
}
Тесты
Console.WriteLine(IncrementString("a") == "b");
Console.WriteLine(IncrementString("z") == "A");
Console.WriteLine(IncrementString("Z") == "aa");
Console.WriteLine(IncrementString("aa") == "ab");
Console.WriteLine(IncrementString("az") == "aA");
Console.WriteLine(IncrementString("aZ") == "ba");
Console.WriteLine(IncrementString("zZ") == "Aa");
Console.WriteLine(IncrementString("Za") == "Zb");
Console.WriteLine(IncrementString("ZZ") == "aaa");
public static class StringStep
{
public static string Next(string str)
{
string result = String.Empty;
int index = str.Length - 1;
bool carry;
do
{
result = Increment(str[index--], out carry) + result;
}
while (carry && index >= 0);
if (index >= 0) result = str.Substring(0, index+1) + result;
if (carry) result = "a" + result;
return result;
}
private static char Increment(char value, out bool carry)
{
carry = false;
if (value >= 'a' && value < 'z' || value >= 'A' && value < 'Z')
{
return (char)((int)value + 1);
}
if (value == 'z') return 'A';
if (value == 'Z')
{
carry = true;
return 'a';
}
throw new Exception(String.Format("Invalid character value: {0}", value));
}
}
разделите входную строку на столбцы и обработайте каждую справа налево, как если бы это была базовая арифметика. Примените любой код, который работает с одним столбцом, к каждому столбцу. Когда вы получаете Z, вы "увеличиваете" следующий левый столбец, используя тот же алгоритм. Если следующей левой колонки нет, поставьте "а".
Мне жаль, что вопрос задан частично. Я отредактировал вопрос так, чтобы он отвечал требованиям, без редактирования функция в конечном итоге будет иметь n раз за шагом увеличивая каждое слово из нижнего регистра a в верхний регистр z без "повторного разбора".
пожалуйста, подумайте о перечитывании вопроса, включая отредактированную часть
вот что я придумал. Я не полагаюсь на преобразование ASCII int и скорее использую массив символов. Это должны сделать именно то, что вы ищете.
public static string Step(this string s)
{
char[] stepChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
char[] str = s.ToCharArray();
int idx = s.Length - 1;
char lastChar = str[idx];
for (int i=0; i<stepChars.Length; i++)
{
if (stepChars[i] == lastChar)
{
if (i == stepChars.Length - 1)
{
str[idx] = stepChars[0];
if (str.Length > 1)
{
string tmp = Step(new string(str.Take(str.Length - 1).ToArray()));
str = (tmp + str[idx]).ToCharArray();
}
else
str = new char[] { stepChars[0], str[idx] };
}
else
str[idx] = stepChars[i + 1];
break;
}
}
return new string(str);
}
Это частный случай системы счисления. Он имеет основание 52. Если вы напишете некоторый парсер и логику вывода, вы можете сделать любую арифметику, очевидно, +1 (++) здесь. Цифры "a" - "z" и "A" до "Z", где "a" - ноль, а " Z " - 51
поэтому вам нужно написать парсер, который берет строку и строит из нее int или long. Эта функция называется StringToInt () и реализуется прямо вперед (преобразует символ в число (0..51) умножьте на 52 и возьмите следующий символ)
и вам нужна обратная функция IntToString, которая также реализует прямо вперед (по модулю int с 52 и преобразует результат в цифру, делит int на 52 и повторяет это, пока int не будет равен null)
с помощью этих функций вы можете делать такие вещи: IntToString (StringToInt ("ZZ") +1 ) // будет"aaa"
вам нужно учитывать A) тот факт, что заглавные буквы имеют меньшее десятичное значение в таблице Ascii, чем строчные. B) таблица не является непрерывной A-Z-a - z-между Z и a есть символы.
public static string stepChar(string str)
{
return stepChar(str, str.Length - 1);
}
public static string stepChar(string str, int charPos)
{
return stepChar(Encoding.ASCII.GetBytes(str), charPos);
}
public static string stepChar(byte[] strBytes, int charPos)
{
//Escape case
if (charPos < 0)
{
//just prepend with a and return
return "a" + Encoding.ASCII.GetString(strBytes);
}
else
{
strBytes[charPos]++;
if (strBytes[charPos] == 91)
{
//Z -> a plus increment previous char
strBytes[charPos] = 97;
return stepChar(strBytes, charPos - 1); }
else
{
if (strBytes[charPos] == 123)
{
//z -> A
strBytes[charPos] = 65;
}
return Encoding.ASCII.GetString(strBytes);
}
}
}
вероятно, вам понадобится некоторая проверка, чтобы убедиться, что входная строка содержит только символы A-Za-z
редактировать убранный код и добавлена новая перегрузка для удаления избыточного байта [] - > строка - > байт[] преобразование
это очень похоже на то, как столбцы Excel будут работать, если они будут неограниченными. Вы можете изменить 52 на ссылочные символы.Длина для более легкого изменения.
static class AlphaInt {
private static string chars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static string StepNext(string input) {
return IntToAlpha(AlphaToInt(input) + 1);
}
public static string IntToAlpha(int num) {
if(num-- <= 0) return "a";
if(num % 52 == num) return chars.Substring(num, 1);
return IntToAlpha(num / 52) + IntToAlpha(num % 52 + 1);
}
public static int AlphaToInt(string str) {
int num = 0;
for(int i = 0; i < str.Length; i++) {
num += (chars.IndexOf(str.Substring(i, 1)) + 1)
* (int)Math.Pow(52, str.Length - i - 1);
}
return num;
}
}
LetterToNum
должна быть функция, которая отображает " a "на 0 и" Z " на 51.
NumToLetter
обратный.
long x = "aazeiZa".Aggregate((x,y) => (x*52) + LetterToNum(y)) + 1;
string s = "";
do { // assertion: x > 0
var c = x % 52;
s = NumToLetter() + s;
x = (x - c) / 52;
} while (x > 0)
// s now should contain the result