The question is complicated but I will explain it in details.
The goal is to make a function which will return next "step" of the given string.
For example
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"
Until here its quite easy, But taking in mind that input IS string it can contain more than 1 characters and the function must behave like this.
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";
and so on...
This doesn't exactly need to extend the base String class.
I tried to work it out by each characters ASCII values but got stuck with strings containing 2 characters.
I would really appreciate if someone can provide full code of the function.
Thanks in advance.
EDIT
*I'm sorry I forgot to mention earlier that the function "reparse" the self generated string when its length reaches 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";
........
I'm sorry I didn't mention it earlier, after reading some answers I realised that the problem was in question.
Without this the function will always produce character "a" n times after the end of the step.
NOTE: This answer is incorrect, as "aa" should follow after "Z"... (see comments below)
Here is an algorithm that might work:
each "string" represents a number to a given base (here: twice the count of letters in the alphabet).
The next step can thus be computed by parsing the "number"-string back into a int, adding 1 and then formatting it back to the base.
Example:
"a" == 1 -> step("a") == step(1) == 1 + 1 == 2 == "b"
Now your problem is reduced to parsing the string as a number to a given base and reformatting it. A quick googling suggests this page: http://everything2.com/title/convert+any+number+to+decimal
How to implement this?
a lookup table for letters to their corresponding number: a=1, b=2, c=3, ... Y = ?, Z = 0
to parse a string to number, read the characters in reverse order, looking up the numbers and adding them up:
"ab" -> 2*BASE^0 + 1*BASE^1
with BASE being the number of "digits" (2 count of letters in alphabet, is that 48?)
EDIT: This link looks even more promising: http://www.citidel.org/bitstream/10117/20/12/convexp.html
Quite collection of approaches, here is mine:-
The Function:
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);
}
The Tests
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));
}
}
Split the input string into columns and process each, right-to-left, like you would if it was basic arithmetic. Apply whatever code you've got that works with a single column to each column. When you get a Z, you 'increment' the next-left column using the same algorithm. If there's no next-left column, stick in an 'a'.
I'm sorry the question is stated partly.
I edited the question so that it meets the requirements, without the edit the function would end up with a n times by step by step increasing each word from lowercase a to uppercase z without "re-parsing" it.
Please consider re-reading the question, including the edited part
This is what I came up with. I'm not relying on ASCII int conversion, and am rather using an array of characters. This should do precisely what you're looking for.
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);
}
This is a special case of a numeral system. It has the base of 52. If you write some parser and output logic you can do any kind of arithmetics an obviously the +1 (++) here.
The digits are "a"-"z" and "A" to "Z" where "a" is zero and "Z" is 51
So you have to write a parser who takes the string and builds an int or long from it. This function is called StringToInt() and is implemented straight forward (transform char to number (0..51) multiply with 52 and take the next char)
And you need the reverse function IntToString which is also implementet straight forward (modulo the int with 52 and transform result to digit, divide the int by 52 and repeat this until int is null)
With this functions you can do stuff like this:
IntToString( StringToInt("ZZ") +1 ) // Will be "aaa"
You need to account for A) the fact that capital letters have a lower decimal value in the Ascii table than lower case ones. B) The table is not continuous A-Z-a-z - there are characters inbetween Z and 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);
}
}
}
You'll probably want some checking in place to ensure that the input string only contains chars A-Za-z
Edit Tidied up code and added new overload to remove redundant byte[] -> string -> byte[] conversion
Proof http://geekcubed.org/random/strIncr.png
This is a lot like how Excel columns would work if they were unbounded. You could change 52 to reference chars.Length for easier modification.
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 should be be a Function that maps "a" to 0 and "Z" to 51.
NumToLetter the inverse.
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
Related
How do I convert numbers to its equivalent alphabet character and convert alphabet character to its numeric values from a string (except 0, 0 should stay 0 for obvious reasons)
So basically if there is a string
string content="D93AK0F5I";
How can I convert it to ?
string new_content="4IC11106E9";
I'm assuming you're aware this is not reversible, and that you're only using upper case and digits. Here you go...
private string Transpose(string input)
{
StringBuilder result = new StringBuilder();
foreach (var character in input)
{
if (character == '0')
{
result.Append(character);
}
else if (character >= '1' && character <= '9')
{
int offset = character - '1';
char replacement = (char)('A' + offset);
result.Append(replacement);
}
else if (character >= 'A' && character <= 'Z') // I'm assuming upper case only; feel free to duplicate for lower case
{
int offset = character - 'A' + 1;
result.Append(offset);
}
else
{
throw new ApplicationException($"Unexpected character: {character}");
}
}
return result.ToString();
}
Well, if you are only going to need a one way translation, here is quite a simple way to do it, using linq:
string convert(string input)
{
var chars = "0abcdefghijklmnopqrstuvwxyz";
return string.Join("",
input.Select(
c => char.IsDigit(c) ?
chars[int.Parse(c.ToString())].ToString() :
(chars.IndexOf(char.ToLowerInvariant(c))).ToString())
);
}
You can see a live demo on rextester.
You can use ArrayList of Albhabets. For example
ArrayList albhabets = new ArrayList();
albhabets.Add("A");
albhabets.Add("B");
and so on.
And now parse your string character by character.
string s = "1BC34D";
char[] characters = s.ToCharArray();
for (int i = 0; i < characters.Length; i++)
{
if (Char.IsNumber(characters[0]))
{
var index = characters[0];
var stringAlbhabet = albhabets[index];
}
else
{
var digitCharacter = albhabets.IndexOf(characters[0]);
}
}
This way you can get "Alphabet" representation of number & numeric representation of "Alphabet".
I have a method which gets two string. These strings can contain numbers, ASCII chars or both at the same time.
The algorithm works like this:
Split both strings into char Arrays A and B.
Try to parse element Ai and Bi to an int
Compare element Ai with element Bi, in case of integers use direct comparison, in case of chars use ordinal string comparison.
Do work based on the result
Now, I'm wondering: Do I really need to parse the elements to int? I simply could compare each element in an ordinal string comparison and would get the same result, right?
What are the performance implications here? Is parsing and normal comparison faster than ordinal string comparison? Is it slower?
Is my assumption (using ordinal string comparison instead of parsing and comparing) correct?
Here is the method in question:
internal static int CompareComponentString(this string componentString, string other)
{
bool componentEmpty = string.IsNullOrWhiteSpace(componentString);
bool otherEmtpy = string.IsNullOrWhiteSpace(other);
if (componentEmpty && otherEmtpy)
{
return 0;
}
if (componentEmpty)
{
return -1;
}
if (otherEmtpy)
{
return 1;
}
string[] componentParts = componentString.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
string[] otherParts = other.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < Math.Min(componentParts.Length, otherParts.Length); i++)
{
string componentChar = componentParts[i];
string otherChar = otherParts[i];
int componentNumVal, otherNumVal;
bool componentIsNum = int.TryParse(componentChar, out componentNumVal);
bool otherIsNum = int.TryParse(otherChar, out otherNumVal);
if (componentIsNum && otherIsNum)
{
if (componentNumVal.CompareTo(otherNumVal) == 0)
{
continue;
}
return componentNumVal.CompareTo(otherNumVal);
}
else
{
if (componentIsNum)
{
return -1;
}
if (otherIsNum)
{
return 1;
}
int comp = string.Compare(componentChar, otherChar, StringComparison.OrdinalIgnoreCase);
if (comp != 0)
{
return comp;
}
}
}
return componentParts.Length.CompareTo(otherParts.Length);
}
This are strings that might be used. I might add only the part after the minus sign is used.
1.0.0-alpha
1.0.0-alpha.1
1.0.0-alpha.beta
1.0.0-beta.2
With this method you can create a compare string for each of your string. These strings are comparable by simple alphanumeric comparison.
Assumptions:
There is a minus in the string separating the common part and the indiv part
before the minus is always a substring of three integer values divided by a dot
These integer values are not higher than 999 (look at variable "MaxWidth1")
behind the minus is another substring consisting of several parts, also divided by a dot
The second substring's parts may be numeric or alphanumeric with a max. width of 7 (look at "MaxWidth2")
The second substring consists of max. 5 parts (MaxIndivParts)
Put this method wherever you want:
public string VersionNumberCompareString(string versionNumber, int MaxWidth1=3, int MaxWidth2=7,int MaxIndivParts=5){
string result = null;
int posMinus = versionNumber.IndexOf('-');
string part1 = versionNumber.Substring(0, posMinus);
string part2 = versionNumber.Substring(posMinus+1);
var integerValues=part1.Split('.');
result = integerValues[0].PadLeft(MaxWidth1, '0');
result += integerValues[1].PadLeft(MaxWidth1, '0');
result += integerValues[2].PadLeft(MaxWidth1, '0');
var alphaValues = part2.Split('.');
for (int i = 0; i < MaxIndivParts;i++ ) {
if (i <= alphaValues.GetUpperBound(0)) {
var s = alphaValues[i];
int casted;
if (int.TryParse(s, out casted)) //if int: treat as number
result += casted.ToString().PadLeft(MaxWidth2, '0');
else //treat as string
result += s.PadRight(MaxWidth2, ' ');
}
else
result += new string(' ', MaxWidth2);
}
return result; }
You call it like this:
var s1 = VersionNumberCompareString("1.3.0-alpha.1.12");
//"001003000alpha 00000010000012 "
var s2 = VersionNumberCompareString("0.11.4-beta");
//"000011004beta "
var s3 = VersionNumberCompareString("2.10.11-beta.2");
//"002010011beta 0000002 "
Be aware of the final " sign. All strings are of the same length!
Hope this helps...
that's .net comparison logic for ascii strings -
private unsafe static int CompareOrdinalIgnoreCaseHelper(String strA, String strB)
{
Contract.Requires(strA != null);
Contract.Requires(strB != null);
Contract.EndContractBlock();
int length = Math.Min(strA.Length, strB.Length);
fixed (char* ap = &strA.m_firstChar) fixed (char* bp = &strB.m_firstChar)
{
char* a = ap;
char* b = bp;
while (length != 0)
{
int charA = *a;
int charB = *b;
Contract.Assert((charA | charB) <= 0x7F, "strings have to be ASCII");
// uppercase both chars - notice that we need just one compare per char
if ((uint)(charA - 'a') <= (uint)('z' - 'a')) charA -= 0x20;
if ((uint)(charB - 'a') <= (uint)('z' - 'a')) charB -= 0x20;
//Return the (case-insensitive) difference between them.
if (charA != charB)
return charA - charB;
// Next char
a++; b++;
length--;
}
return strA.Length - strB.Length;
}
}
having said that, Unless you have a strict performance constaint, i would say if you get the same result from an already implemented & tested function, its better to reuse it and not to reinvent the wheel.
It saves so much time in implementation, unit testing, debugging & bug fixing time. & helps keep the software simple.
How can I implement a function in c# that return the immediate text character of a given text character. The characters should be in alphabetic order.
Example: given the character "C" the method should return the character "D".
char c = 'C';
char i = (char)(c + 1);
System.Diagnostics.Debug.WriteLine(i);
It will output 'D' to the Debug Output window.
Here's a method that should do what you want. There is no checking for non-alpha characters though.
public static string ToNextAlpha(string str)
{
if (str == null)
{
throw new ArgumentNullException("str");
// Or you can just return "a";
}
var end = new StringBuilder();
for (int index = str.Length - 1; index >= 0; index--)
{
char c = str[index];
bool isZed = c == 'z' || c == 'Z';
c = (char)(isZed ? c - 25 : c + 1);
end.Insert(0, c);
if (!isZed)
{
return str.Substring(0, index) + end;
}
}
return "a" + end;
}
Note: This will turn "zz" into "aaa" and "ZZ" into "aAA". If you want to prepend an upper case "A" just change the last line with whatever logic you need.
I think I have found the solution:
public static string GetNextLetter(string letter = null)
{
if (IsStringNullOrEmpty(letter))
return "A";
char lastLetter = letter.Last();
if (lastLetter.ToString() == "Z")
return GetNextLetter(RemoveLastCharacter(letter)) + "A";
else
return RemoveLastCharacter(letter) + (char)(lastLetter + 1);
}
Any better solutions are welcome.
I am inventing an algorithm in which i have created a new number which is "z" (not actually z) and i am using it with the old numbers (0123456789) and my new series of number looks like this (0123456789z) but the problem here is that how to write a program that gives "19 + 1" as "z" and "z + 1" as "20".
Try something like this, though you'd have to implement additional coding for parameter checking and incrementing the second to last character if the last character reaches 0.
This is the basic logic:
private const string DIGITS = "0123456789z";
static void Main(string[] args)
{
Console.WriteLine(NextValue("9"));
Console.ReadKey();
}
private static string NextValue(string value)
{
char nextChar = '\0';
if(!string.IsNullOrEmpty(value))
{
char lastChar = value[value.Length - 1];
int nextCharIndex = DIGITS.IndexOf(lastChar) + 1;
if (nextCharIndex > DIGITS.Length)
nextChar = DIGITS[0];
else
nextChar = DIGITS[nextCharIndex];
}
return nextChar.ToString();
}
After you edited your question, I think what you're after is this
public int incrementNumber(string number)
{
var lastNumber = int.Parse(number.Last());
return (number.Length - 1) + ((lastNumber + 1) % 10).ToString();
}
% 10 or Mod 10 takes the reminder of the number divided by 10. So if you pass in 9 it will increment to 10 then wrap around to 0. When you pass in 5 it will increment to 6 and stay as 6 because it's not divisible by 10.
This may not be optimized but works if you allow +1 to increment.
public static string NextValue(string Counting)
{
int nextVal;
if(int.TryParse(Counting, out nextVal))
{
return (nextVal + 1).ToString();
}
else
{
char[] numbers = Counting.ToCharArray();
StringBuilder incremented = new StringBuilder();
foreach (char digit in numbers.Reverse())
{
if (digit == 'z')
{
incremented.Append("0");
}
else if (int.TryParse(digit.ToString(), out nextVal))
{
nextVal = nextVal + 1;
if (nextVal == 10)
{
incremented.Append("z");
}
else
{
incremented.Append(nextVal.ToString());
}
incremented.Append(string.Concat(numbers.Reverse().Skip(incremented.Length)));
break;
}
else
{
//Invalid character in number except for z
return string.Empty;
}
}
if (incremented[incremented.Length - 1] == '0')
incremented.Append("1");
return Reverse(incremented.ToString());
}
}
public static string Reverse(string s)
{
char[] charArray = s.ToCharArray();
Array.Reverse(charArray);
return new string(charArray);
}
I've got binary number and I need to:
1) negate all bytes
2) add 1 to negate number
So, I wrote this:
public string u2_number_plus = "1001";
public string u2_number_minus = "";
public string binToU2()
{
int length = u2_number_plus.Length;
int temp = 1;
//negate all bytes
for (int a = 0; a < length; a++)
{
if (u2_number_plus[a] == '1')
u2_number_minus += '0';
else
u2_number_minus += '1';
}
//add 1 to my new (because negate) number
for (int b = length - 1; b >= 0; b--)
{
if (u2_number_minus[b] == 0 && temp == 1)
{
u2_number_minus = u2_number_minus.Replace(u2_number_minus[b], '1');
temp = 0;
}
else if (u2_number_minus[b] == 1 && temp == 1)
{
u2_number_minus = u2_number_minus.Replace(u2_number_minus[b], '0');
temp = 1;
}
else
break;
}
return u2_number_minus;
}
My function binToU2() returns negate but not increment value.
If input data is 1001 I should get 0111, but function returns just 0110. Where I made a mistake?
When you are doing the checking of u2_number_minus[b] you need to compare it against '0' and '1' not the number 0 and 1.
if (u2_number_minus[b] == '0' && temp == 1)
There is also another error, the use of Replace changes all occurrences of the specified character in the string, but we only want to change the one at the specified position. C# does not have replaceAt, but a helper function can be created to do this. See Replacing a char at a given index in string?. I used Jon Skeet's code here:
public static class ReplaceHelper
{
public static string ReplaceAt(this string input, int index, char newChar)
{
if (input == null)
{
throw new ArgumentNullException("input");
}
char[] chars = input.ToCharArray();
chars[index] = newChar;
return new string(chars);
}
}
and change the Replace lines to use ReplaceAt eg
u2_number_minus = u2_number_minus.ReplaceAt(b, '1');
don't really get what you want to do or where you need this for, but anyways, maybe you want to use a BitArray instead of struggling with string manipulation.
BitArray is actually storing bits and gives you basic functionality to negate the array or use other operations...
Let me give you an example:
// define a bit array with length=4 and false as default value for each bit.
var bits = new BitArray(4, false);
bits.Not(); // negate --> all 4 bits are now true.
// your example:
bits = new BitArray(new bool[] { true, false, false, true });
// to inverst/negate it
bits.Not();
// convert to string:
string bitString = string.Empty;
foreach (var bit in bits)
{
bitString += (bool)bit ? "1" : "0";
}
Console.WriteLine(bitString);
// from string:
string longBitString = "01000101001001010100010010010";
var longIntArray = longBitString.ToCharArray().Select(p => p.Equals('0') ? false : true).ToArray();
var longBitArray = new BitArray(longIntArray);