Increment a unique field with specified character pattern - c#

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);
}

Related

Convert oct to dex integer

Incorrectly converts a number
In the program you need to convert from octal number system to decimal
"a" is a integer class field that uses the GetDex() method
Construct - this.a = a;
public int GetDex()
{
int res = 0;
int exp = 1;
for (int i = Convert.ToString(a).Length - 1; i >= 0; i--)
{
res += exp * Convert.ToInt32(Convert.ToString(a)[i]);
exp *= 8;
}
return res;
}
The problem is in the
Convert.ToInt32(Convert.ToString(a)[i])
fragment. You actually add ascii codes, not digits. To get digit integer 5 from character '5' just subtract '0':
(Convert.ToString(a)[i] - '0')
Your code corrected:
public int GetDex()
{
int res = 0;
int exp = 1;
for (int i = Convert.ToString(a).Length - 1; i >= 0; i--)
{
//DONE: you should add digits, not ascii codes: - '0'
res += exp * (Convert.ToString(a)[i] - '0');
exp *= 8;
}
return res;
}
You can put it compact with a help of Linq:
public int GetDex() => a
.ToString()
.Aggregate(0, (s, i) => s * 8 + i - '0');

Check patterns of 5 in password "12345", "abcde"

I'm trying to validate a password string in a .NET for sequential patterns (forward or reverse) with numbers or letters of 5 or more.
Examples of patterns that will not be accepted:
"ABCDE",
"12345",
"54321",
"edcba"
I cannot find a decent regex pattern that handles finding the characters in order, currently just returning any sequence of 5 letters or numbers:
public bool CheckForSequence(string input)
{
return Regex.IsMatch(input.ToUpper(), #"([A-Z])(?!\1)([A-Z])(?!\1|\2)([A-Z])(?!\1|\2|\3)([A-Z])(?!\1|\2|\3|\4)([A-Z])") ||
Regex.IsMatch(input, #"([1-9])(?!\1)([1-9])(?!\1|\2)([1-9])(?!\1|\2|\3)([1-9])(?!\1|\2|\3|\4)([1-9])");
}
There are probably way better ways to do this, but, just for fun, I've made a simple brute-force algorithm:
bool CheckForSequence(string inp) {
bool InRange(int c) {
const int minLower = (int)'a';
const int maxLower = (int)'z';
const int minUpper = (int)'A';
const int maxUpper = (int)'Z';
const int minNumber = (int)'0';
const int maxNumber = (int)'9';
return (c >= minLower && c <= maxLower) || (c >= minUpper && c <= maxUpper) || (c >= minNumber && c <= maxNumber);
}
if(inp.Length < 5) return false;
for(var i = 0; i < inp.Length - 4; i++)
{
var c = (int)inp[i];
if(InRange(c))
{
var vM = c;
int x;
for(x = i+1; x < i + 5; x++)
{
if(inp[x] != vM+1 || !InRange(inp[x])) break;
vM++;
}
if(x == i+5) return true;
for(x = i+1; x < i + 5; x++)
{
if(inp[x] != vM-1 || !InRange(inp[x])) break;
vM--;
}
if(x == i+5) return true;
}
}
return false;
}
You can see it in action in this fiddle
Wiktor is correct - regex is the wrong tool for this.
Here's one possible implementation:
public static class SequenceChecker
{
private static char MapChar(char c) => c switch
{
>= '0' and <= '9' => c,
>= 'A' and <= 'Z' => c,
>= 'a' and <= 'z' => (char)(c - 'a' + 'A'),
_ => default,
};
private static bool IsSequence(ReadOnlySpan<char> input)
{
char x = MapChar(input[0]);
if (x == default) return false;
char y = MapChar(input[1]);
if (y == default) return false;
int direction = y - x;
if (Math.Abs(direction) != 1) return false;
for (int index = 2; index < input.Length; index++)
{
x = y;
y = MapChar(input[index]);
if (y == default) return false;
int nextDirection = y - x;
if (nextDirection != direction) return false;
}
return true;
}
public static bool ContainsSequence(string input, int sequenceLength = 5)
{
if (sequenceLength < 2) throw new ArgumentOutOfRangeException(nameof(sequenceLength));
if (input is null) return false;
if (input.Length < sequenceLength) return false;
for (int startIndex = 0; startIndex < 1 + input.Length - sequenceLength; startIndex++)
{
if (IsSequence(input.AsSpan(startIndex, sequenceLength)))
{
return true;
}
}
return false;
}
}
Just to add to the plethora of solutions posted so far:
public static int LongestAscendingOrDescendingRun(string s)
{
if (s.Length <= 1)
return 0;
int longest = 0;
int current = 0;
bool ascending = false;
for (int i = 1; i < s.Length; i++)
{
bool isAscending () => s[i]-s[i-1] == +1;
bool isDescending() => s[i]-s[i-1] == -1;
if (current > 0)
{
if (ascending)
{
if (isAscending())
{
longest = Math.Max(longest, ++current);
}
else // No longer ascending.
{
current = 0;
}
}
else // Descending.
{
if (isDescending())
{
longest = Math.Max(longest, ++current);
}
else // No longer descending.
{
current = 0;
}
}
}
else // No current.
{
if (isAscending())
{
ascending = true;
current = 2;
longest = Math.Max(longest, current);
}
else if (isDescending())
{
ascending = false;
current = 2;
longest = Math.Max(longest, current);
}
}
}
return longest;
}
Like Wiktor has already said, regex isn't a good way to do this. You could find the difference between consecutive characters of the string, and complain if you find a sequence of four or more ones (or -1s).
public bool CheckForSequence(string pass)
{
int curr_diff = 0; // The difference between the i-1th and i-2th character
int consec_diff = 0; // The number of consecutive pairs having the same difference
for (int i = 1; i < pass.Length; i++)
{
int diff = pass[i] - pass[i - 1]; // The difference between the ith and i-1th character
if (Math.Abs(diff) == 1 && curr_diff == diff)
{
// If the difference is the same, increment consec_diff
// And check if the password is invalid
consec_diff++;
if (consec_diff >= 4)
return false;
}
else
{
// New diff. reset curr_diff and consec_diff
curr_diff = diff;
consec_diff = Math.Abs(diff)==1 ? 1 : 0;
// If the difference is 1, set consec_diff to 1 else 0
}
}
return consec_diff < 4;
}

Serial key generation xor string encryption

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

Calculating Gematrical Value of a String in C# without Using a Dictionary

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.

Counting number of vowels in a string

I have a textbox where the user enters a random string. I want to count the number of vowels(A,E,I,O,U) in the string and show th results in the labelcontrol.
protected void Button1_Click(object sender, EventArgs e)
{
string EnterString;
EnterString = TextBox1.Text;
char ch1 = 'a';
char ch2 = 'e';
char ch3 = 'i';
char ch4 = 'o';
char ch5 = 'u';
int counta = 0;
int counte = 0;
int counti = 0;
int counto = 0;
int countu = 0;
char ch6 = 'A';
char ch7 = 'E';
char ch8 = 'I';
char ch9 = 'O';
char ch10 = 'U';
int countA = 0;
int countE = 0;
int countI = 0;
int countO = 0;
int countU = 0;
//const string vowels = "aeiou";
/* return value.Count(chr => vowels.Contains(char.ToLower(chr)));
return Value.Count()*/
int j = counta + counte + counti + counto + countu + countA + countE + countI + countO + countU;
foreach (char v in EnterString)
{
if (v == ch1) { counta++; j++; }
else if (v == ch2) { counte++; j++; }
else if (v == ch3) { counti++; j++; }
else if (v == ch4) { counto++; j++; }
else if (v == ch5) { countu++; j++; }
}
foreach (char v in EnterString)
{
if (v == ch6) { countA++; j++; }
else if (v == ch7) { countE++; j++; }
else if (v == ch8) { countI++; j++; }
else if (v == ch9) { countO++; j++; }
else if (v == ch10) { countU++; j++; }
}
Label1.Text = j.ToString();
}
You have this in your code:
const string vowels = "aeiou";
return value.Count(chr => vowels.Contains(char.ToLower(chr)));
That works, at least if your culture is US. So no idea why you commented it out in favor of the current monstrosity.
On a Turkish locale it will fail because the lower case of I is not i but ı (undotted). So if you define vowels as aeiouAEIOU you should use ToLowerInvariant.
But if you want to include other vowels (like Ä) I have no idea how to do that except by listing all the characters.
Full implementation:
int CountVowels(string value)
{
const string vowels = "aeiou";
return value.Count(chr => vowels.Contains(char.ToLowerInvariant(chr)));
}
Looks like you got the good code part from:
Counting vowels using switch
int vowel = 0;
Console.WriteLine("Please enter the string:");
string main = Console.ReadLine();
for (int j = 0; j < main.Length ; j++)
{
if (main[j] == 'a' || main[j] == 'A' || main[j] == 'e' || main[j] == 'E' || main[j] == 'i' || main[j] == 'I' || main[j] == 'o' || main[j] == 'O' || main[j] == 'u' || main[j] == 'U')
{
vowel++;
}
}
Console.WriteLine("Number of vowels in sentence is :"+ vowel);
Console.ReadLine();
Console.WriteLine("Please input your text: ")
mystring = Console.ReadLine
For i = 1 To mystring.Length
Console.Write((mystring(i - 1)) & ",")
isItAVowel = False
If mystring(i - 1) = "a" Or mystring(i - 1) = "A" Then isItAVowel = True
If mystring(i - 1) = "e" Or mystring(i - 1) = "E" Then isItAVowel = True
If mystring(i - 1) = "i" Or mystring(i - 1) = "I" Then isItAVowel = True
If mystring(i - 1) = "o" Or mystring(i - 1) = "O" Then isItAVowel = True
If mystring(i - 1) = "u" Or mystring(i - 1) = "U" Then isItAVowel = True
If isItAVowel Then
This could help good luck
private void button1_Click(object sender, EventArgs e)
{
string EnterString;
EnterString = textBox1.Text;
const string vowels = "aeiou";
label1.Text = EnterString.Count(myString => vowels.Contains(char.ToLowerInvariant(myString))).ToString();
}
public static void Main()
{
char[] sentence = new char[100];
int i, vowels = 0, consonants = 0, special = 0, n;
Console.WriteLine("Enter the Length of the sentence \n");
n = int.Parse(Console.ReadLine());
for (i = 0; i < n; i++)
{
sentence[i] = Convert.ToChar(Console.Read());
}
for (i = 0; sentence[i] != '\0'; i++)
{
if ((sentence[i] == 'a' || sentence[i] == 'e' || sentence[i] ==
'i' || sentence[i] == 'o' || sentence[i] == 'u') ||
(sentence[i] == 'A' || sentence[i] == 'E' || sentence[i] ==
'I' || sentence[i] == 'O' || sentence[i] == 'U'))
{
vowels = vowels + 1;
}
else
{
consonants = consonants + 1;
}
if (sentence[i] == 't' || sentence[i] == '\0' || sentence[i] == ' ')
{
special = special + 1;
}
}
consonants = consonants - special;
Console.WriteLine("No. of vowels {0}", vowels);
Console.WriteLine("No. of consonants {0}", consonants);
Console.ReadLine();
Console.ReadLine();
}
#include <bits/stdc++.h>
using namespace std;
int main()
{
int t;
cin >> t;
set<char> vowels = {'A', 'E', 'I', 'O', 'U', 'a', 'e', 'i', 'o', 'u'};
while(t--)
{
string s;
int c = 0;
cin >> s;
for(char i : s)
if(vowels.find(i) != vowels.end())
++c;
cout << c << "\n";
}
return 0;
}
string vowelList = ("aeiouAEIOU");
int i = 0;
int j = 0;
int vowelCount = 0;
string main = textBox1.Text; /or Console.ReadLine();
while (j < main.Length)
{
while (i < vowelList.Length)
{
if (main[j] == vowelList[i])
{
vowelCount++;
}
i++;
}
j = j + 1;
i = 0;
}
label1.Text = ("Number of vowels in sentence is :" + vowelCount); /or Console.Writeline ("Number of vowels in sentence is: " + vowelCount
count = 0
string=input("Enter string:")
vowels = set("aeiouAEIOU")
for letter in string:
if letter in vowels:
count += 1
print("Count of the vowels is:")
print(count)

Categories