The code below attempts to calculate the gematrical value of a string:
for (int i = 0; i < str.Length; i++){
switch(str[i].ToString()){
case "A":
gemValue += 1;
break;
case "a":
gemValue += 1;
break;
case "B":
gemValue += 2;
break;
case "b":
gemValue += 2;
break;
// other characters to follow
default:
gemValue += 0;
break;
}
}
Console.WriteLine("The gematrical value of the word or phrase is " +
gemValue);
Console.ReadKey();
Could there be a way to simplify the code and logic without using a dictionary (or any sort of array for that matter)?
Creating a list of ints like:
int A, a = 1;
int B, b = 2;
...
is no better than plugging all cases into switch. I thought about playing foul and just grabbing the ascii value for each char but that is also to be avoided in this exercise.
Any ideas?
string sample = "abc";
int sum = (from c in sample select char.IsLetter(c) ? char.IsUpper(c) ? c - 'A' + 1 : c - 'a' + 1 : 0).Sum();
Console.WriteLine("The gematrical value of the word or phrase is {0}", sum);
You can
string str = "Hello";
int gemValue = 0;
for (int i = 0; i < str.Length; i++)
{
char ch = str[i];
if (ch >= 'A' && ch <= 'Z')
{
gemValue += ch - 'A' + 1;
}
else if (ch >= 'a' && ch <= 'z')
{
gemValue += ch - 'a' + 1;
}
}
because in the end, chars are numbers with a range 0-65535, where A = 65, B = 66, ..., Z = 90, a = 97, b = 98, ... z = 122.
Note that the world is a big and funny place, full of marvelous languages that don't simply use A-Za-z.
string str = "Hèållo"; // Doesn't work with æ, ø
int gemValue = 0;
string str2 = string.Concat(
str.Normalize(NormalizationForm.FormD)
.Where(x => CharUnicodeInfo.GetUnicodeCategory(x) != UnicodeCategory.NonSpacingMark));
for (int i = 0; i < str.Length; i++)
{
char ch = str2[i];
if (ch >= 'A' && ch <= 'Z')
{
gemValue += ch - 'A' + 1;
}
else if (ch >= 'a' && ch <= 'z')
{
gemValue += ch - 'a' + 1;
}
else if (char.IsLetter(ch))
{
throw new NotSupportedException(string.Format("{0} contains non A-Z letters", str));
}
}
This will at least try to solve the problem for some letters, like àèéìòù (and many others), converting them to aeeiou and will throw a NotSupportedException if you try to pass letters that it doesn't recognize (like æ, ø, arabic, japanese, chinese, ...). Note that it will ignore non-letters, like spaces, commas, dots, ...
You can create dictionary of lowercase char values, and then project each char to value in simple LINQ query:
var str = "aBb";
var letterValues = new Dictionary<char, int> {
{'a', 1},
{'b', 2}
};
int gemValue = str.Select(Char.ToLower)
.Sum(ch => letterValues.Contains(ch) ? letterValues[ch] : 0);
Or for better performance you can use TryGetValue method to avoid double lookup of chars which contained in dictionary:
int gemValue = 0;
foreach (var ch in str.Select(Char.ToLower))
{
int value;
if (letterValues.TryGetValue(ch, out value))
gemValue += value;
}
This should work:
int minLetter = (int) 'A' - 1;
int sum = "Hello World".Sum(c => (int)Char.ToUpper(c) - minLetter);
Tested successfully with:
var coll = new[] { "a", "A", "aA", "AA", "abc", "ABC", "AbC", "123", "hello World" };
foreach (string str in coll)
{
int sum = str.Sum(c => (int)Char.ToUpper(c) - minLetter);
Console.WriteLine(sum);
}
However, as commented by vc74, if the value associated to a letter does not depend on its position in the alphabet a dictionary is the best way to map each letter to its value.
Related
I am trying to find a way to increment a user defined idenitifer. I have written something that achieves what I want the code to do, but I highly doubt it's the best way to do this:
The character pattern is:
AAA000
AAA999
BAA000
BAA999
BBA000
And so on, although:
AAA000
AAA999
BAA000
BAA999
CAA000
Would be acceptable.
Here is my code to just generate that pattern:
int i = 30;
char char1 = 'A';
char char2 = 'A';
char char3 = 'A';
double number = 998;
for (int j = 0; j < i; j++)
{
string id = $"{char1}{char2}{char3}{number.ToString().PadLeft(3, '0')}";
if (number == 999)
{
number = 998;
if (char1 == char2 && char1 == char3 && char1 != 'Z')
{
char1++;
}
else if (char1 > char2 && char2 != 'Z')
{
char2++;
}
else if (char3 != 'Z')
{
char3++;
}
}
else
{
number++;
}
Console.WriteLine(id);
}
To clarify, I need to build a function that can take the latest value, for example:
DEF123
which in turn will return:
DEF124
Or DEF999 which will return DEG000.
Using Maximillians answer, I have amended the method:
static void NextId(string highestId)
{
char startChar1 = highestId[0];
char startChar2 = highestId[1];
char startChar3 = highestId[2];
int startNumber = int.Parse(highestId.Substring(highestId.Length - 3));
int n = 1;
int i = 0;
for (char char1 = startChar1; char1 <= 'Z' && i < n; char1++)
{
for (char char2 = startChar2; char2 <= 'Z' && i < n; char2++)
{
for (char char3 = startChar3; char3 <= 'Z' && i < n; char3++)
{
for (int number = startNumber; number < 1000 && i < n; number++)
{
string id = $"{char1}{char2}{char3}{number.ToString().PadLeft(3, '0')}";
Console.WriteLine(id);
i++;
}
}
}
}
}
This is almost perfect, except:
DEZ998 returns DEZ998, DEZ999 being the highest id passed in returns DEZ999.
Any recommendations on achieving this would be a great help.
I had to do some assumptions on your pattern, but as far as I understood your question I'd use nested loops instead one loop to rule them all.
int n = 30;
int i = 0;
for (char char1 = 'A'; char1 <= 'Z' && i < n; char1++)
{
for (char char2 = 'A'; char2 <= 'Z' && i < n; char2++)
{
for (char char3 = 'A'; char3 <= 'Z' && i < n; char3++)
{
for(int number = 0; number < 1000 && i < n; number++)
{
string id = $"{char1}{char2}{char3}{number.ToString().PadLeft(3, '0')}";
Console.WriteLine(id);
i++;
}
}
}
}
This will:
Increment the number from 0 to 999
Afterwards it'll increment Char1 by one and start again at (1.) until Z is reached
Afterwards it'll increment Char2 by one and start again at (2.) until Z is reached
Afterwards it'll increment Char3 by one and start again at (3.) until Z is reached
It will stop at any point if the maximum amount(n) is reached
→ You will get a maximum amout of 17575999 possible unique ID's
Update:
The method GetNextId(Tuple<char, char, char, int> id) could help you for that. It calculates the next ID depending on the previous one.
void GenerateIDs()
{
char char1 = 'B';
char char2 = 'F';
char char3 = 'A';
int number = 159;
int n = 30;
// this one is the current ID
var iterationId = new Tuple<char, char, char, int>(char1, char2, char3, number);
for(int i = 1; i < n; i++)
{
iterationId = GetNextId(iterationId);
Console.WriteLine(IdToString(iterationId));
}
}
/// returns: c1Next, c2Next, c3Next, numberNext
private Tuple<char, char, char, int> GetNextId(Tuple<char, char, char, int> id)
{
var number = id.Item4 + 1;
var c3 = id.Item3;
var c2 = id.Item2;
var c1 = id.Item1;
if(number > 999)
{
number = 0;
c3++;
if(c3 > 'Z')
{
c3 = 'A';
c2++;
if (c2 > 'Z')
{
c2 = 'A';
c1++;
if(c1 > 'Z')
{
throw new IndexOutOfRangeException("Next ID bigger than \"ZZZ999\"");
}
}
}
}
return new Tuple<char, char, char, int>(c1, c2, c3, number);
}
private string IdToString(Tuple<char, char, char, int> id)
{
return $"{id.Item1}{id.Item2}{id.Item3}{id.Item4.ToString().PadLeft(3, '0')}";
}
Alternatevly
You could just store an int to the database and use the values 0 to 17575999 and then calculate the display ID
private string IntToId(int intId)
{
var number = intId % 1000;
intId /= 1000;
char c3 = (char) ('A' + (intId % 26));
intId /= 26;
var c2 = (char) ('A' + (intId % 26));
intId /= 26;
var c1 = (char) ('A' + (intId % 26));
return $"{c1}{c2}{c3}{number.ToString().PadLeft(3, '0')}";
}
private int IdToInt(string id)
{
int c1 = id[0] - 'A';
int c2 = id[1] - 'A';
int c3 = id[2] - 'A';
int number = Int32.Parse(id.Substring(3));
return ((((((c1 * 26) + c2) *26) + c3) * 1000) + number);
}
When I do an xor on a string I get special characters
private void btnEncryptDecrypt_Click(object sender, EventArgs e)
{
byte[] bytes = Encoding.UTF8.GetBytes(keyTextBox.Text);
textTextBox.Text = string.Empty;
foreach (byte i in bytes)
{
byte c = Convert.ToByte(i ^ Convert.ToByte(textBox1.Text));
textTextBox.Text = textTextBox.Text + Convert.ToChar(c);
}
}
62FA7AC4 1234567890 xor to !%QV VT#7&%$#"! /.'
I want to use it for serial key generation with only alphanumeric characters
I want to pass "62FA7AC4", a date and a number between 0 and 5000 and a few random dummy numbers
Input will be "62FA7AC4"+"2500"+"21/05/2018"
Output should be something like "5QBK-J4D1-8CF6-5MW2-78FZ-2FPL-4S6S-CTGB"
What am I doing Wrong?
Try working with numbers, not strings:
using System.Numerics;
...
// Let's use BigInteger for arbitrary long values
BigInteger left = BigInteger.Parse("62FA7AC4", NumberStyles.HexNumber);
BigInteger right = BigInteger.Parse("1234567890", NumberStyles.HexNumber);
string result = (left ^ right).ToString("X");
Console.Write(result);
So you have
1256AC0254
Edit: As far as I can see you want alphanumeric (i.e. Base 36 == 26 letters + 10 digits output). You can use the same approach: operate with integer(s), not string(s)
private static Random s_Random = new Random();
...
BigInteger value = BigInteger.Parse(
"0" + // we don't want negative values
"62FA7AC4" + // header
s_Random.Next(5001).ToString("0000") + // random in [0..5000] range
DateTime.Today.ToString("ddMMyyyy"), // Date like 21052018
NumberStyles.HexNumber);
Then do any xor (if you like):
value ^= some_secret_value;
Finally represent the value in base 36:
private static String ToBase36(BigInteger value) {
List<char> list = new List<char>();
for (int index = 0; value > 0; value /= 36, index++) {
if (index > 0 && index % 4 == 0)
list.Add('-');
BigInteger v = value % 36;
list.Add(v < 10 ? (char)('0' + v) : (char) ('A' + v - 10));
}
list.Reverse();
return string.Concat(list);
}
Test:
BigInteger value = BigInteger.Parse(
"0" +
"62FA7AC4" +
"2500" +
DateTime.Today.ToString("ddMMyyyy"),
NumberStyles.HexNumber);
string result = ToBase36(value);
Console.Write(result);
Outcome:
2443-WNC5-AVBB-M32W
Edit 2: To restore the original number
private static BigInteger FromBase36(string value) {
BigInteger result = 0;
BigInteger power = 1;
for (int i = value.Length - 1; i >= 0; --i) {
char item = value[i];
if (item >= '0' && item <= '9') {
result += power * (item - '0');
power *= 36;
}
else if (item >= 'A' && item <= 'Z') {
result += power * (item - 'A' + 10);
power *= 36;
}
else if (item >= 'a' && item <= 'z') {
result += power * (item - 'a' + 10);
power *= 36;
}
}
return result;
}
e.g.
BigInteger value = BigInteger.Parse(
"0" +
"62FA7AC4" +
"2500" +
DateTime.Today.ToString("ddMMyyyy"),
NumberStyles.HexNumber);
string result = ToBase36(value);
BigInteger back = FromBase36(result);
Console.WriteLine(string.Join(Environment.NewLine, value, result, back));
Outcome:
467412447575903165554712
2443-WNC5-AVBB-M32W
467412447575903165554712
How can I insert a string between two strings if a condition is true?
Let's say we have an array of characters that we want to check if the first word ends with one of them and the second word starts with one of them.
For example "Go home" will pass the condition because "o" and "h" are letters that will meet requirement (=> Go ___ home)
char[] toCheck = {'h','o','d', 'g'};
string sentence = "Go home";
List<string> words = sentence.Split(' ').ToList();
for (int i = 0; i < words.Count - 1; i++)
{
if (toCheck.Any(x=> x == words[i][words[i].Length - 1]) &&
(toCheck.Any(x=> x == words[i + 1][0])))
{
words.Insert(i,"_between");
}
}
return words.Aggregate("", (current, word) => current + (word + " "));
My problem is that this is returning "_between Go _between home" instead of "Go _between home" and I can't find out why.
Thank you for your help.
Here's a method you could use to do this that will return a sequence of the words instead of inserting into the original collection.
private static IEnumerable<string> InsertBetween(
this IList<string> words,
char[] characters,
string insertValue)
{
for (int i = 0; i < words.Count - 1; i++)
{
yield return words[i];
if (characters.Contains(words[i].Last()) && characters.Contains(words[i + 1][0]))
yield return insertValue;
}
if (words.Count > 0)
yield return words[words.Count - 1];
}
Then running this
char[] toCheck = { 'h', 'o', 'd', 'g' };
string sentence = "Go home";
Console.WriteLine(string.Join(" ", sentence.Split().InsertBetween(toCheck, "_between")));
Will give you
Go _between home
I just think it's better to avoid mutating a colleciton that you are looping over, but if you do you need to increment the index when you do an insert so you move past the inserted value and you have to insert in the correct position.
for (int i = 0; i < words.Count - 1; i++)
{
if (toCheck.Any(x => x == words[i][words[i].Length - 1]) &&
(toCheck.Any(x => x == words[i + 1][0])))
{
words.Insert(i + 1, "_between");
i++;
}
}
Consider doing it a very straight-forward way by having the resulting sentence stored in a new string:
char[] toCheck = { 'h', 'o', 'd', 'g' };
string sentence = "Go home";
string finalsentence = "";
List<string> words = sentence.Split(' ').ToList();
for (int i = 0; i < words.Count - 1; i++) {
if (toCheck.Any(x => x == words[i][words[i].Length - 1]) &&
(toCheck.Any(x => x == words[i + 1][0]))) {
finalsentence = words[i] + "_between" + words[i + 1] + " ";
}
}
return finalsentence;
That being said, if you want to make your current method words, you should refer to insert in index i + k (with incremented k starting from 1, thanks to juharr) rather than i and using string.Join, not aggregate:
char[] toCheck = { 'h', 'o', 'd', 'g' };
string sentence = "Go home";
int k = 1;
List<string> words = sentenc;e.Split(' ').ToList();
for (int i = 0; i < words.Count - 1; i++) {
if (toCheck.Any(x => x == words[i][words[i].Length - 1]) &&
toCheck.Any(x => x == words[i + 1][0])) {
words.Insert(i + k++, "_between");
}
}
return string.Join(" ", words);
"My problem is that this is returning "_between Go _between home" instead of "Go _between home" and I can't find out why."
Because yours i index in words.Insert(i,"_between"); is starting from 0. You could change the code on many ways, but based on your question, if you want to keep it, just don't words.Insert(i,"_between"); for i==0.
Hope this helps...
I am making a Caesar cipher and I want to make the letters in a loop so for example if the letter 'z' needs to be shifted it should go back to 'a' for both capital and lowercase.
//Array that holds each char in the plaintext inputed is declared and initiated
char[] chars = plainTextInput.ToCharArray();
//For loop that will go through each letter and change the value of each letter by adding the shiftAmount
for (int i = 0; i < plainTextInput.Length; ++i)
{
chars[i] = (char)(((int)chars[i]) + shiftAmount);
if (chars[i] >= 97 && chars[i] <= 122)
{
if (chars[i] > 122)
{
int x = chars[i] - 123;
chars[i] = (char)((int)(97 + x));
}
}
}
//Variable for ciphertext output holds char array chars as a string
cipherTextOutput = new string(chars);
If I input 'xyz' and shift by one I get 'yz{'.
Use modulo arithmetic:
new_pos = (current_pos + shift) % 26
current_pos has to be the relative letter position (eg: a=0, b=1... z=25). Something like:
if ('A' <= c && c <= 'Z') // uppercase
{
current_pos = (int) c - (int) 'A';
}
else if ('a' <= c && c <= 'z') // lowercase
{
current_pos = (int) c - (int) 'a';
}
See working demo: http://ideone.com/NPZbT
That being said, I hope this is just code you are playing with, and not something to be used in real code.
Is there an easy way to generate an array containing the letters of the alphabet in C#? It's not too hard to do it by hand, but I was wondering if there was a built in way to do this.
I don't think there is a built in way, but I think the easiest would be
char[] alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
C# 3.0 :
char[] az = Enumerable.Range('a', 'z' - 'a' + 1).Select(i => (Char)i).ToArray();
foreach (var c in az)
{
Console.WriteLine(c);
}
yes it does work even if the only overload of Enumerable.Range accepts int parameters ;-)
for (char letter = 'A'; letter <= 'Z'; letter++)
{
Debug.WriteLine(letter);
}
char[] alphabet = Enumerable.Range('A', 26).Select(x => (char)x).ToArray();
I wrote this to get the MS excel column code (A,B,C, ..., Z, AA, AB, ..., ZZ, AAA, AAB, ...) based on a 1-based index. (Of course, switching to zero-based is simply leaving off the column--; at the start.)
public static String getColumnNameFromIndex(int column)
{
column--;
String col = Convert.ToString((char)('A' + (column % 26)));
while (column >= 26)
{
column = (column / 26) -1;
col = Convert.ToString((char)('A' + (column % 26))) + col;
}
return col;
}
Assuming you mean the letters of the English alphabet...
for ( int i = 0; i < 26; i++ )
{
Console.WriteLine( Convert.ToChar( i + 65 ) );
}
Console.WriteLine( "Press any key to continue." );
Console.ReadKey();
You could do something like this, based on the ascii values of the characters:
char[26] alphabet;
for(int i = 0; i <26; i++)
{
alphabet[i] = (char)(i+65); //65 is the offset for capital A in the ascaii table
}
(See the table here.) You are just casting from the int value of the character to the character value - but, that only works for ascii characters not different languages etc.
EDIT:
As suggested by Mehrdad in the comment to a similar solution, it's better to do this:
alphabet[i] = (char)(i+(int)('A'));
This casts the A character to it's int value and then increments based on this, so it's not hardcoded.
Note also, the string has a operator[] which returns a Char, and is an IEnumerable<char>, so for most purposes, you can use a string as a char[]. Hence:
string alpha = "ABCDEFGHIJKLMNOPQRSTUVQXYZ";
for (int i =0; i < 26; ++i)
{
Console.WriteLine(alpha[i]);
}
foreach(char c in alpha)
{
Console.WriteLine(c);
}
Surprised no one has suggested a yield solution:
public static IEnumerable<char> Alphabet()
{
for (char letter = 'A'; letter <= 'Z'; letter++)
{
yield return letter;
}
}
Example:
foreach (var c in Alphabet())
{
Console.Write(c);
}
var alphabets = Enumerable.Range('A', 26).Select((num) => ((char)num).ToString()).ToList();
char alphaStart = Char.Parse("A");
char alphaEnd = Char.Parse("Z");
for(char i = alphaStart; i <= alphaEnd; i++) {
string anchorLetter = i.ToString();
}
//generate a list of alphabet using csharp
//this recurcive function will return you
//a string with position of passed int
//say if pass 0 will return A ,1-B,2-C,.....,26-AA,27-AB,....,701-ZZ,702-AAA,703-AAB,...
static string CharacterIncrement(int colCount)
{
int TempCount = 0;
string returnCharCount = string.Empty;
if (colCount <= 25)
{
TempCount = colCount;
char CharCount = Convert.ToChar((Convert.ToInt32('A') + TempCount));
returnCharCount += CharCount;
return returnCharCount;
}
else
{
var rev = 0;
while (colCount >= 26)
{
colCount = colCount - 26;
rev++;
}
returnCharCount += CharacterIncrement(rev-1);
returnCharCount += CharacterIncrement(colCount);
return returnCharCount;
}
}
//--------this loop call this function---------//
int i = 0;
while (i <>
{
string CharCount = string.Empty;
CharCount = CharacterIncrement(i);
i++;
}
4 ways get English alphabet in Console:
public void ShowEnglishAlphabet()
{
var firstLetter = 'a';
var endLetter = 'z';
for (var letter = firstLetter; letter <= endLetter; letter++)
{
Console.WriteLine($"{letter}-{letter.ToString().ToUpper()}");
}
}
public void ShowEnglishAlphabetFromUnicodeTableDecNumber()
{
var firstLetter = 97;
var endLetter = 122;
for (var letterNumberUnicodeTable = firstLetter;
letterNumberUnicodeTable <= endLetter; letterNumberUnicodeTable++)
{
Console.WriteLine($"{(char)letterNumberUnicodeTable}-
{((char)letterNumberUnicodeTable).ToString().ToUpper()}");
}
}
public void ShowEnglishAlphabetUnicodeTableEscapeSequence()
{
var firstLetter = '\u0061';
var endLetter = '\u007A';
for (var letterNumberUnicodeTable = firstLetter;
letterNumberUnicodeTable <= endLetter; letterNumberUnicodeTable++)
{
Console.WriteLine($"{letterNumberUnicodeTable}-
{letterNumberUnicodeTable.ToString().ToUpper()}");
}
}
public void ShowEnglishAlphabetUnicodeTableLinq()
{
var alphabets = Enumerable.Range('a', 26).Select(letter =>
((char)letter).ToString()).ToList();
foreach (var letter in alphabets)
{
Console.WriteLine($"{letter}-{letter.ToUpper()}");
}
}
Unfortunately there is no ready-to-use way.
You can use;
char[] characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();