Related
I was working on straightforward encryption and got stuck on one of its rules.
The rules are,
Encryption work by adding 5 to each character.
Only encrypt a-z and A-Z, all other characters will add to the encrypted string as it is.
If the character is z or Z, the adding starts from the character a.
By performing the above encryption in reverse, the description should also be present.
I was able to do the encryption, but the 3rd rule is where I got stuck when decrypting.
Below is the code I tried,
# Encrypt
Input : Dinindu-12Z
Output : Insnsiz-12F
# Decrypt
Input : Insnsiz-12F
Output : Dinindu-12Z # This is the expected output, but got "Dinind\-12A"
using System;
class Program
{
public static String encrypt(String input)
{
String output = "";
foreach (char c in input)
{
if (char.IsLetter(c))
{
char cc = c;
if (c == 'z') cc = 'a';
if (c == 'Z') cc = 'A';
output += (char)(((int)cc) + 5);
}
else
{
output += c;
}
}
return output;
}
public static string decrypt(String input)
{
String output = "";
foreach (char c in input)
{
if (char.IsLetter(c))
{
char cc = c;
if (c == 'z') cc = 'a';
if (c == 'Z') cc = 'A';
output += (char)(((int)cc) - 5);
}
else
{
output += c;
}
}
return output;
}
public static void Main(string[] args)
{
String a = encrypt("Dinindu-12Z");
String b = decrypt(a);
Console.WriteLine(a);
Console.WriteLine(b);
}
}
You should write a method that will accept a char array and get the element at the advanced index. You can use the modulo (%) operator to advance and wrap, e.g.
private static char GetCharWithStepAndWrap(char[] chars, char ch, int step)
{
var index = Array.IndexOf(chars, ch);
index += step;
index %= chars.Length;
return chars[index];
}
Adding the step value will advance the index, possibly past the end of the array. The modulo will then divide the index by the Length of the array and use the remainder. That means that if the index starts within the array, it will stay where it is and, if it's past the end of the array, you're effectively subtracting the Length from it to wrap back to the beginning.
You can then use that method with a char array from a to z to encrypt and then simply reverse the array to decrypt, e.g.
static void Main(string[] args)
{
var chars = Enumerable.Range(Convert.ToInt32('a'), 26).Select(Convert.ToChar).ToArray();
var plainText = "Dinindu-12Z";
var encryptedText = string.Empty;
for (var i = 0; i < plainText.Length; i++)
{
var ch = plainText[i];
if (char.IsLetter(ch))
{
var isUpper = char.IsUpper(ch);
ch = char.ToLower(ch);
ch = GetCharWithStepAndWrap(chars, ch, 5);
if (isUpper)
{
ch = char.ToUpper(ch);
}
}
encryptedText += ch;
}
Console.WriteLine(encryptedText);
Array.Reverse(chars);
var decryptedText = string.Empty;
for (var i = 0; i < plainText.Length; i++)
{
var ch = encryptedText[i];
if (char.IsLetter(ch))
{
var isUpper = char.IsUpper(ch);
ch = char.ToLower(ch);
ch = GetCharWithStepAndWrap(chars, ch, 5);
if (isUpper)
{
ch = char.ToUpper(ch);
}
}
decryptedText += ch;
}
Console.WriteLine(decryptedText);
}
If you try that code, you'll notice that the correct encrypted text is "Insnsiz-12E".
I have a question about iterate through the Alphabet.
I would like to have a loop that begins with "a" and ends with "z". After that, the loop begins "aa" and count to "az". after that begins with "ba" up to "bz" and so on...
Anybody know some solution?
Thanks
EDIT: I forgot that I give a char "a" to the function then the function must return b. if u give "bnc" then the function must return "bnd"
First effort, with just a-z then aa-zz
public static IEnumerable<string> GetExcelColumns()
{
for (char c = 'a'; c <= 'z'; c++)
{
yield return c.ToString();
}
char[] chars = new char[2];
for (char high = 'a'; high <= 'z'; high++)
{
chars[0] = high;
for (char low = 'a'; low <= 'z'; low++)
{
chars[1] = low;
yield return new string(chars);
}
}
}
Note that this will stop at 'zz'. Of course, there's some ugly duplication here in terms of the loops. Fortunately, that's easy to fix - and it can be even more flexible, too:
Second attempt: more flexible alphabet
private const string Alphabet = "abcdefghijklmnopqrstuvwxyz";
public static IEnumerable<string> GetExcelColumns()
{
return GetExcelColumns(Alphabet);
}
public static IEnumerable<string> GetExcelColumns(string alphabet)
{
foreach(char c in alphabet)
{
yield return c.ToString();
}
char[] chars = new char[2];
foreach(char high in alphabet)
{
chars[0] = high;
foreach(char low in alphabet)
{
chars[1] = low;
yield return new string(chars);
}
}
}
Now if you want to generate just a, b, c, d, aa, ab, ac, ad, ba, ... you'd call GetExcelColumns("abcd").
Third attempt (revised further) - infinite sequence
public static IEnumerable<string> GetExcelColumns(string alphabet)
{
int length = 0;
char[] chars = null;
int[] indexes = null;
while (true)
{
int position = length-1;
// Try to increment the least significant
// value.
while (position >= 0)
{
indexes[position]++;
if (indexes[position] == alphabet.Length)
{
for (int i=position; i < length; i++)
{
indexes[i] = 0;
chars[i] = alphabet[0];
}
position--;
}
else
{
chars[position] = alphabet[indexes[position]];
break;
}
}
// If we got all the way to the start of the array,
// we need an extra value
if (position == -1)
{
length++;
chars = new char[length];
indexes = new int[length];
for (int i=0; i < length; i++)
{
chars[i] = alphabet[0];
}
}
yield return new string(chars);
}
}
It's possible that it would be cleaner code using recursion, but it wouldn't be as efficient.
Note that if you want to stop at a certain point, you can just use LINQ:
var query = GetExcelColumns().TakeWhile(x => x != "zzz");
"Restarting" the iterator
To restart the iterator from a given point, you could indeed use SkipWhile as suggested by thesoftwarejedi. That's fairly inefficient, of course. If you're able to keep any state between call, you can just keep the iterator (for either solution):
using (IEnumerator<string> iterator = GetExcelColumns())
{
iterator.MoveNext();
string firstAttempt = iterator.Current;
if (someCondition)
{
iterator.MoveNext();
string secondAttempt = iterator.Current;
// etc
}
}
Alternatively, you may well be able to structure your code to use a foreach anyway, just breaking out on the first value you can actually use.
Edit: Made it do exactly as the OP's latest edit wants
This is the simplest solution, and tested:
static void Main(string[] args)
{
Console.WriteLine(GetNextBase26("a"));
Console.WriteLine(GetNextBase26("bnc"));
}
private static string GetNextBase26(string a)
{
return Base26Sequence().SkipWhile(x => x != a).Skip(1).First();
}
private static IEnumerable<string> Base26Sequence()
{
long i = 0L;
while (true)
yield return Base26Encode(i++);
}
private static char[] base26Chars = "abcdefghijklmnopqrstuvwxyz".ToCharArray();
private static string Base26Encode(Int64 value)
{
string returnValue = null;
do
{
returnValue = base26Chars[value % 26] + returnValue;
value /= 26;
} while (value-- != 0);
return returnValue;
}
The following populates a list with the required strings:
List<string> result = new List<string>();
for (char ch = 'a'; ch <= 'z'; ch++){
result.Add (ch.ToString());
}
for (char i = 'a'; i <= 'z'; i++)
{
for (char j = 'a'; j <= 'z'; j++)
{
result.Add (i.ToString() + j.ToString());
}
}
I know there are plenty of answers here, and one's been accepted, but IMO they all make it harder than it needs to be. I think the following is simpler and cleaner:
static string NextColumn(string column){
char[] c = column.ToCharArray();
for(int i = c.Length - 1; i >= 0; i--){
if(char.ToUpper(c[i]++) < 'Z')
break;
c[i] -= (char)26;
if(i == 0)
return "A" + new string(c);
}
return new string(c);
}
Note that this doesn't do any input validation. If you don't trust your callers, you should add an IsNullOrEmpty check at the beginning, and a c[i] >= 'A' && c[i] <= 'Z' || c[i] >= 'a' && c[i] <= 'z' check at the top of the loop. Or just leave it be and let it be GIGO.
You may also find use for these companion functions:
static string GetColumnName(int index){
StringBuilder txt = new StringBuilder();
txt.Append((char)('A' + index % 26));
//txt.Append((char)('A' + --index % 26));
while((index /= 26) > 0)
txt.Insert(0, (char)('A' + --index % 26));
return txt.ToString();
}
static int GetColumnIndex(string name){
int rtn = 0;
foreach(char c in name)
rtn = rtn * 26 + (char.ToUpper(c) - '#');
return rtn - 1;
//return rtn;
}
These two functions are zero-based. That is, "A" = 0, "Z" = 25, "AA" = 26, etc. To make them one-based (like Excel's COM interface), remove the line above the commented line in each function, and uncomment those lines.
As with the NextColumn function, these functions don't validate their inputs. Both with give you garbage if that's what they get.
Here’s what I came up with.
/// <summary>
/// Return an incremented alphabtical string
/// </summary>
/// <param name="letter">The string to be incremented</param>
/// <returns>the incremented string</returns>
public static string NextLetter(string letter)
{
const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (!string.IsNullOrEmpty(letter))
{
char lastLetterInString = letter[letter.Length - 1];
// if the last letter in the string is the last letter of the alphabet
if (alphabet.IndexOf(lastLetterInString) == alphabet.Length - 1)
{
//replace the last letter in the string with the first leter of the alphbat and get the next letter for the rest of the string
return NextLetter(letter.Substring(0, letter.Length - 1)) + alphabet[0];
}
else
{
// replace the last letter in the string with the proceeding letter of the alphabet
return letter.Remove(letter.Length-1).Insert(letter.Length-1, (alphabet[alphabet.IndexOf(letter[letter.Length-1])+1]).ToString() );
}
}
//return the first letter of the alphabet
return alphabet[0].ToString();
}
just curious , why not just
private string alphRecursive(int c) {
var alphabet = "abcdefghijklmnopqrstuvwxyz".ToCharArray();
if (c >= alphabet.Length) {
return alphRecursive(c/alphabet.Length) + alphabet[c%alphabet.Length];
} else {
return "" + alphabet[c%alphabet.Length];
}
}
This is like displaying an int, only using base 26 in stead of base 10. Try the following algorithm to find the nth entry of the array
q = n div 26;
r = n mod 26;
s = '';
while (q > 0 || r > 0) {
s = alphabet[r] + s;
q = q div 26;
r = q mod 26;
}
Of course, if you want the first n entries, this is not the most efficient solution. In this case, try something like daniel's solution.
I gave this a go and came up with this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Alphabetty
{
class Program
{
const string alphabet = "abcdefghijklmnopqrstuvwxyz";
static int cursor = 0;
static int prefixCursor;
static string prefix = string.Empty;
static bool done = false;
static void Main(string[] args)
{
string s = string.Empty;
while (s != "Done")
{
s = GetNextString();
Console.WriteLine(s);
}
Console.ReadKey();
}
static string GetNextString()
{
if (done) return "Done";
char? nextLetter = GetNextLetter(ref cursor);
if (nextLetter == null)
{
char? nextPrefixLetter = GetNextLetter(ref prefixCursor);
if(nextPrefixLetter == null)
{
done = true;
return "Done";
}
prefix = nextPrefixLetter.Value.ToString();
nextLetter = GetNextLetter(ref cursor);
}
return prefix + nextLetter;
}
static char? GetNextLetter(ref int letterCursor)
{
if (letterCursor == alphabet.Length)
{
letterCursor = 0;
return null;
}
char c = alphabet[letterCursor];
letterCursor++;
return c;
}
}
}
Here is something I had cooked up that may be similar. I was experimenting with iteration counts in order to design a numbering schema that was as small as possible, yet gave me enough uniqueness.
I knew that each time a added an Alpha character, it would increase the possibilities 26x but I wasn't sure how many letters, numbers, or the pattern I wanted to use.
That lead me to the code below. Basically you pass it an AlphaNumber string, and every position that has a Letter, would eventually increment to "z\Z" and every position that had a Number, would eventually increment to "9".
So you can call it 1 of two ways..
//This would give you the next Itteration... (H3reIsaStup4dExamplf)
string myNextValue = IncrementAlphaNumericValue("H3reIsaStup4dExample")
//Or Loop it resulting eventually as "Z9zzZzzZzzz9zZzzzzzz"
string myNextValue = "H3reIsaStup4dExample"
while (myNextValue != null)
{
myNextValue = IncrementAlphaNumericValue(myNextValue)
//And of course do something with this like write it out
}
(For me, I was doing something like "1AA000")
public string IncrementAlphaNumericValue(string Value)
{
//We only allow Characters a-b, A-Z, 0-9
if (System.Text.RegularExpressions.Regex.IsMatch(Value, "^[a-zA-Z0-9]+$") == false)
{
throw new Exception("Invalid Character: Must be a-Z or 0-9");
}
//We work with each Character so it's best to convert the string to a char array for incrementing
char[] myCharacterArray = Value.ToCharArray();
//So what we do here is step backwards through the Characters and increment the first one we can.
for (Int32 myCharIndex = myCharacterArray.Length - 1; myCharIndex >= 0; myCharIndex--)
{
//Converts the Character to it's ASCII value
Int32 myCharValue = Convert.ToInt32(myCharacterArray[myCharIndex]);
//We only Increment this Character Position, if it is not already at it's Max value (Z = 90, z = 122, 57 = 9)
if (myCharValue != 57 && myCharValue != 90 && myCharValue != 122)
{
myCharacterArray[myCharIndex]++;
//Now that we have Incremented the Character, we "reset" all the values to the right of it
for (Int32 myResetIndex = myCharIndex + 1; myResetIndex < myCharacterArray.Length; myResetIndex++)
{
myCharValue = Convert.ToInt32(myCharacterArray[myResetIndex]);
if (myCharValue >= 65 && myCharValue <= 90)
{
myCharacterArray[myResetIndex] = 'A';
}
else if (myCharValue >= 97 && myCharValue <= 122)
{
myCharacterArray[myResetIndex] = 'a';
}
else if (myCharValue >= 48 && myCharValue <= 57)
{
myCharacterArray[myResetIndex] = '0';
}
}
//Now we just return an new Value
return new string(myCharacterArray);
}
}
//If we got through the Character Loop and were not able to increment anything, we retun a NULL.
return null;
}
Here's my attempt using recursion:
public static void PrintAlphabet(string alphabet, string prefix)
{
for (int i = 0; i < alphabet.Length; i++) {
Console.WriteLine(prefix + alphabet[i].ToString());
}
if (prefix.Length < alphabet.Length - 1) {
for (int i = 0; i < alphabet.Length; i++) {
PrintAlphabet(alphabet, prefix + alphabet[i]);
}
}
}
Then simply call PrintAlphabet("abcd", "");
public static string shita1(string st1)
{
string st2 = "", stemp = st1;
int i;
for(i=0; i<stemp.Length; i++)
{
if (stemp.IndexOf("cbc") == i)
{
i += 2 ;
stemp = "";
stemp = st1.Substring(i);
i = 0;
}
else
st2 = st2 + stemp[i];
}
return st2;
}
static void Main(string[] args)
{
string st1;
Console.WriteLine("enter one string:");
st1 = Console.ReadLine();
Console.WriteLine(shita1(st1));
}
}
i got a challange from my college, the challange is to move any "cbc" characters from a string...
this is my code... it works when i use only one "cbc" but when i use 2 of them it stucks... help please :)
The IndexOf Method gives you everything you need to know.
Per the documentation.
Reports the zero-based index of the first occurrence of a specified
Unicode character or string within this instance. The method returns
-1 if the character or string is not found in this instance.
This means you can create a loop that repeats as long as the returned index is not -1 and you don't have to loop through the string testing letter by letter.
I think this should work just tested it on some examples. Doesn't use string.Replace or IndexOf
static void Main(string[] args)
{
Console.WriteLine("enter one string:");
var input = Console.ReadLine();
Console.WriteLine(RemoveCBC(input));
}
static string RemoveCBC(string source)
{
var result = new StringBuilder();
for (int i = 0; i < source.Length; i++)
{
if (i + 2 == source.Length)
break;
var c = source[i];
var b = source[i + 1];
var c2 = source[i + 2];
if (c == 'c' && c2 == 'c' && b == 'b')
i = i + 2;
else
result.Append(source[i]);
}
return result.ToString();
}
You can use Replace to remove/replace all occurances of a string inside another string:
string original = "cbc_STRING_cbc";
original = original.Replace("cbc", String.Empty);
If you want remove characters from string using only IndexOf method you can use this code.
public static string shita1(string st1)
{
int index = -1;
string yourMatchingString = "cbc";
while ((index = st1.IndexOf(yourMatchingString)) != -1)
st1 = st1.Remove(index, yourMatchingString.Length);
return st1;
}
This code remove all inputs of you string.
But you can do it just in one line:
st1 = st1.Replace("cbc", string.Empty);
Hope this help.
I am looking to generate a Sequence Number in this format
00000A
00000B
00000B
and so on till
00000Z
and then
00001A
00001B
00001C
...
00001Z
...
00010A
till
99999Z
I know that I can generate Max 2.6 million rows using this method but I guess that is enough
so, if I have the a String, lets say 26522C, Now i want the next number as 26522D
or If I have 34287Z, i want 34288A
I can write the Algorithm about it but there will be lots of parsing of the input string characters by characters
I was wondering is there any easier way of doing it
String GetNextNumberInSequence(String inputString)
{
if (inputString.Length == 6)
{
var charArray = inputString.ToCharArray();
char[] inputChars = { charArray[0], charArray[1], charArray[2],charArray[3],charArray[4],charArray[5] };
if(Char.IsDigit(charArray[5]))
{
//Parse first 5 characters
}
}
}
private static String GetNextNumberInSequence(String inputString)
{
var integerpart = int.Parse(inputString.Substring(0, 5));
var characterPart = inputString[5];
if (characterPart == 'Z')
return string.Format("{0}{1}", (++integerpart).ToString("D5"), "A");
var nextChar = (char)(characterPart + 1);
return string.Format("{0}{1}", (integerpart).ToString("D5"), nextChar.ToString());
}
You can achieve this by converting a number to Base36.
Take a look at this sample:
private const string CharList = "0123456789abcdefghijklmnopqrstuvwxyz";
public static String Base36Encode(long input, char paddingChar, int totalWidth)
{
char[] clistarr = CharList.ToCharArray();
var result = new Stack<char>();
while (input != 0)
{
result.Push(clistarr[input % 36]);
input /= 36;
}
return new string(result.ToArray()).PadLeft(totalWidth, paddingChar).ToUpper();
}
and then use it this way:
for(int i = 0; i < 1000; i++)
{
Debug.WriteLine(Base36Encode(i, '0', 6));
}
which will produce this:
000000, 000001, 000002, 000003, 000004, 000005, 000006, 000007, 000008, 000009, 00000A, 00000B, 00000C, 00000D, 00000E, 00000F, 00000G, 00000H, 00000I, 00000J, 00000K, 00000L, 00000M, 00000N, 00000O, 00000P, 00000Q, 00000R, 00000S, 00000T, 00000U, 00000V, 00000W, 00000X, 00000Y, 00000Z, 000010, 000011, 000012, 000013, 000014, 000015, 000016, 000017, 000018, 000019, 00001A, 00001B, 00001C, 00001D, 00001E, 00001F, 00001G, 00001H, 00001I, 00001J, 00001K, 00001L, 00001M, 00001N, 00001O, 00001P, 00001Q, 00001R, 00001S, 00001T, 00001U, 00001V, 00001W, 00001X, 00001Y, 00001Z, 000020, 000021, 000022, 000023, 000024, 000025, 000026, 000027, 000028, 000029, 00002A, 00002B, 00002C, 00002D, 00002E, 00002F, 00002G, 00002H, 00002I, 00002J, 00002K, 00002L, 00002M, 00002N, 00002O, 00002P, 00002Q, 00002R, 00002S, 00002T...
and the positive thing about this approach is that you can convert this back to number by using:
public static Int64 Base36Decode(string input)
{
var reversed = input.ToLower().Reverse();
long result = 0;
int pos = 0;
foreach (char c in reversed)
{
result += CharList.IndexOf(c) * (long)Math.Pow(36, pos);
pos++;
}
return result;
}
How we can find out the next character of the entered one. For example, if I entered the character "b" then how do I get the answer "c"?
Try this:
char letter = 'c';
if (letter == 'z')
nextChar = 'a';
else if (letter == 'Z')
nextChar = 'A';
else
nextChar = (char)(((int)letter) + 1);
This way you have no trouble when the char is the last of the alphabet.
How about:
char first = 'c';
char nextChar = (char)((int) first + 1);
Note that a char will implicitly cast to an int. Here's a simplified solution:
char incrementCharacter(char input)
{
return (input == 'z'? 'a': (char)(input + 1));
}
Perhaps the simplest way is a little function and an array of the 26 chars. Then you can decide what you want to return for 'z'.
Convert the character to a number, increment the number and then convert back.
But consider what will happen for "z" or "á" (Latin Small Leter A with Acute).
This Change value useful for Excel application to find previous column
public static string PrevExecelColumn( string s)
{
s = s.ToUpper();
char[] ac = s.ToCharArray();
int ln = ac.Length;
for (int i = ln - 1; i > -1; i--)
{
char c = ac[i];
if (c == 'A')
{
ac[i] = 'Z';
continue;
}
ac[i] = (char)(((int)ac[i]) - 1);
break;
}
s = new string(ac);
return s;
}
Try this :
public string GetNextAlphabetLetter(int indice) {
return ((char)('A' + indice)).ToString();
}
need to just add 1 in character you get next character.
It works on ASCII values.