Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I'm a beginner at c# and how could I write a code that will check if:
the first 3 characters are letters
the next 3 are numbers,
next two letters
And the last character a number.
And if it is isn't write an error message.
I've tried using Substring(0,3) and putting it against Char.IsLetter just to attempt but failed.
Here's a correct way to do it using char.IsLetter and char.IsNumber.
if(myString.Length == 9
&& char.IsLetter(myString[0])
&& char.IsLetter(myString[1])
&& char.IsLetter(myString[2])
&& char.IsNumber(myString[3])
&& char.IsNumber(myString[4])
&& char.IsNumber(myString[5])
&& char.IsLetter(myString[6])
&& char.IsLetter(myString[7])
&& char.IsNumber(myString[8]))
{
// match.
}
Basically you have validate the length of the string, and then validate each character.
You could also use char.IsDigit to limit the match to radix-10 digit versus char.IsNumber that will match any Unicode character that is deemed a number (fractions, subscripts, superscripts, Roman numerals, currency numerators, encircled numbers, and script-specific digits). Also char.IsLetter will also match any Unicode character that is deemed a letter which will stray outside of the basic A-Z. To restrict numbers to 0-9 and letters to A-Z you could do this instead.
public static IsAtoZ(char c)
{
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
}
if(myString.Length == 9
&& IsAtoZ(myString[0])
&& IsAtoZ(myString[1])
&& IsAtoZ(myString[2])
&& char.IsDigit(myString[3])
&& char.IsDigit(myString[4])
&& char.IsDigit(myString[5])
&& IsAtoZ(myString[6])
&& IsAtoZ(myString[7])
&& char.IsDigit(myString[8]))
{
// match.
}
But honestly at this point a regular expression will be more terse. But note that you'll still have to consider if you want to match Unicode characters and use the correct regular expression based on that.
you can use a regex
bool isMatch= Regex.IsMatch("abc123de4", #"\p{L}{3}\d{3}\p{L}{2}\d");
You could just use a regular expression:
var regex = new Regex("^[a-z]{3}[0-9]{2}[a-z]{2}[0-9]{1}$", RegexOptions.IgnoreCase);
var matces = regex.Matches(input);
where input is the string you want to check.
When we pass the option RegexOptions.IgnoreCase to the constructor of the Regex, we say that it doesn't matter if the letters are capital or not.
You could avoid to specify this parameter and state explicitly that you want both capital and small letters, as Rahul has correctly pointed out in his comment. This is done like below:
var regex = new Regex("^[a-z][A-Z]{3}[0-9]{2}[a-z][A-Z]{2}[0-9]{1}$");
var matces = regex.Matches(input);
You can access the individual characters of a string in C# like this:
string s = "1test";
char c = s[0];
c will be '1' one then.
In the next step you can use the Char.IsNumber Method which returns a bool. Just like this:
if(c.IsNumber()){}
Then you do the same thing for the next two chars except that you use the Char.IsLetter method.
I think there are several elegant ways to do this. Since you said that you're a beginner to C#, I would suggest just finding the easiest (most pseudo-code-like, IMHO) way to just express the problem/solution:
private bool MatchesPattern(string test)
{
// can't possibly match the pattern with less than 9 chars
if (test.Length < 9) return false;
int idx = 0;
// test are letters
for (int steps = 1; steps <= 3; steps++)
{
if (!char.IsLetter(test[idx++])) return false;
}
// test are numbers
for (int steps = 1; steps <= 3; steps++)
{
if (!char.IsNumber(test[idx++])) return false;
}
// test are letters
for (int steps = 1; steps <= 2; steps++)
{
if (!char.IsLetter(test[idx++])) return false;
}
// test last char is number
if (!char.IsNumber(test.Last())) return false;
return true;
}
You can test the results:
private void Test(string testValue)
{
if (!MatchesPattern(testValue))
{
Console.WriteLine("Error!");
}
}
Related
Having learned the basics/fundamentals of the C# programming language, I am now trying to tackle my first real-world problem: Write a program that, given a string, finds its longest sub-string that contains at least one upper-case letter but no digits (and then displays the length of this longest sub-string). This could be two qualifying conditions for an acceptable password, for example...
I have written the code below all by myself, which means there is probably performance issues, but that is for later consideration. I am stuck at the point where I have to make sure there is no digit in the sub-string. The comments in my code show my thinking while writing the program...
I thought first I should check to see if there is an upper-case letter in an extracted sub-string, and if there was, then I can store that qualifying sub-string in a list and then break out of the loop. But now I wonder how to check the no-digit condition at the same time in the same sub-string?
I am trying to keep it neat and simple (as I said I have only just started writing programs longer than a few lines!) so I thought doing a nested loop to check every character against !char.IsNumber(letter) might not be optimal. Or should I first check to see if there is no digit, then see if there is at least a capital character?
I feel confused how to achieve both restrictions, so I would appreciate some help in resolving this issue. I would also appreciate any observations or suggestions you might have. For example, is it OK to store my sub-strings in a list? Should I make a dictionary of some sort? Is my all-possible-sub-string extraction nested-loop optimal?
p.s. Some bits are still unfinished; for example I am still to implement the last step to find the longest sub-string and display to the user its length...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PasswordRestriction
{
class Program /// Write a program that, given a string, finds the longest substring that is a valid password and returns its length.
{
static void Main(string[] args)
{
// Ask the user for an alphanumeric string.
Console.WriteLine("Enter a string of alphanumeric values:");
// Receive the user input as string.
string password = Console.ReadLine();
// Print the length of the longest qualifying substring of the user string.
Console.WriteLine("Length of the longest qualifying substring:\n" + Solution(password).Length );
// Prevent the console window from closing.
Console.ReadLine();
}
/// The method that exracts the longest substring that is a valid password.
/// Note that a substring is a 'contiguous' segment of a string.
public static string Solution(string str)
{
// Only allow non-empty strings.
if ( String.IsNullOrEmpty(str) )
{
return "";
}
else
{
// Only allow letters and digits.
if ( str.All(char.IsLetterOrDigit) )
{
// A list for containing qualifying substrings.
List<string> passwordList = new List<string>();
// Generate all possible substrings. Note that
// string itself is not a substring of itself!
for (int i = 1; i < str.Length; i++)
{
for (int j = 0; j <= (str.Length-i); j++)
{
string subStr = str.Substring(j, i);
Console.WriteLine(subStr);
bool containsNum = false;
bool containsUpper = false;
// Convert the substrings to arrays of characters with ToCharArray.
// This method is called on a string and returns a new character array.
// You can manipulate this array in-place, which you cannot do with a string.
char[] subStrArray = subStr.ToCharArray();
// Go through every character in each substring.
// If there is at least one uppercase letter and
// no digits, put the qualifying substring in a list.
for (int k = 0; k < subStrArray.Length; k++)
{
char letter = subStrArray[k];
if ( char.IsNumber(letter) )
{
containsNum = true;
break;
}
if ( char.IsUpper(letter) )
{
containsUpper = true;
}
if ( containsUpper && (containsNum == false) && (k == subStrArray.Length - 1) )
{
Console.WriteLine("Found the above legit password!");
passwordList.Add(subStr);
}
}
}
}
//Find the longest stored string in the list.
//if (passwordList.Count != 0)
//{
string maxLength = passwordList[0];
foreach (string s in passwordList)
{
if (s.Length > maxLength.Length)
{
maxLength = s;
}
}
//}
// Return the qualifying substring.
return maxLength;
}
else
{
return "aaaaaaaaaa";
}
}
}
}
}
A good problem for Linq
contains no digits - Split on digits
at least one upper-case letter - Where + Any
longest (not shortest) OrderByDescending
longest (just one) - FirstOrDefault
Implementation
string source = ....
var result = source
.Split('0', '1', '2', '3', '4', '5', '6', '7', '8', '9')
.Where(line => line.Any(c => c >= 'A' && c <= 'Z')) // or char.IsUpper(c)
.OrderByDescending(line => line.Length)
.FirstOrDefault(); // null if there're no such substrings at all
As an alternative to the Linq answer, and if I understand you correctly, this is what I'd do, replacing the content of the str.All condition:
string qualifier;
string tempQualifier;
bool containsUpper = false;
for (int i = 0; i < str.Length(); i++) {
tempQualifier += str[i];
if (char.IsNumber(str[i])) {
if (containsUpper) {
if (tempQualifier.Length > qualifier.Length && tempQualifier.Length != str.Length) {
qualifier = tempQualifier;
}
containsUpper = false;
}
tempQualifier = "";
} else if (char.IsUpper(str[i])) {
containsUpper = true;
}
}
return qualifier;
This would go through the string, building up the substring until it comes across a number. If the substring contains an uppercase letter and is longer than any previous qualifier, it is stored as the new qualifier (also assuming that it isn't the length of the string provided). Apologies if I've made any mistakes (I'm not well versed in C#).
It's much longer than the Linq answer, but I thought it'd be handy for you to see the process broken down so you can understand it better.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
In my organization, users must generate a password from numbers only (keypads are used to access), minimum length is 8 numbers. How can I make sure the password the user generats is not too weak (using c# on server procossing password change request), applying the following rule:
3 following numbers (even a part of password) are not sequential or repeated (9451238401 or 543555784)
The regular expression is:
^((?!(?<ch>.)\k<ch>\k<ch>)(?!012|123|234|345|456|567|678|789|890)[0-9]){8,}$
The (?!(?<ch>.)\k<ch>\k<ch>) will check for the same character repeated thrice. Note that for the various contiguous sequences I had to put them in a list of possible sequences, (?!012|123|234|345|456|567|678|789|890). [0-9] is the character that will be accepted as valid. The {8,} is for the minimum length.
If you want a general-purpose approach which tells you the number of repeated, ascending and descending digits:
static void checkStrength(string text, out int maxRepeats, out int maxAscending, out int maxDescending)
{
maxRepeats = 0;
maxAscending = 0;
maxDescending = 0;
int currRepeats = 0;
int currAscending = 0;
int currDescending = 0;
for (int i = 1; i < text.Length; ++i)
{
char curr = text[i];
char prev = text[i-1];
if (curr - prev == -1)
maxDescending = Math.Max(maxDescending, ++currDescending);
else
currDescending = 1;
if (curr - prev == 1)
maxAscending = Math.Max(maxAscending, ++currAscending);
else
currAscending = 1;
if (curr == prev)
maxRepeats = Math.Max(maxRepeats, ++currRepeats);
else
currRepeats = 1;
}
}
You would have to call this and then do what you want with the results:
int maxRepeats, maxAscending, maxDescending;
checkStrength(text, out maxRepeats, out maxAscending, out maxDescending);
if (maxRepeats > REPEAT_LIMIT || maxAscending > ASCENDING_LIMIT || maxDescending > DESCENDING_LIMIT)
{
// ... report error or whatever
}
If you don't need to vary the allowed number of repeated or ascending digits, then xanatos' regex is clearly by far the shortest code. This code is only needed if you need to vary the allowed counts at runtime.
while (asteriskWord != hangCharacters && score < 5)
{
while ( letter != ) //This is where I want to test for A-Z a-z
{
Console.WriteLine("Enter a letter please");
letter = Convert.ToChar(Console.ReadLine());
}
}
After the first while-loop I want to be able to place the input inside of a while loop that breaks if the value is = letters A-Z or a-z.
This is so that if the user enters the wrong information, the loop will continue to ask for the information.
Thank you for your time and consideration. Also I tried doing letter != 'A' && letter != 'a'...... and so on, but it didn't work for some reason.
Characters can be compared to each other, just like numbers:
while (!((letter >= 'A' && letter <= 'Z') || (letter >= 'a' && letter <= 'z'))) {
Console.WriteLine("Enter a letter please");
letter = Convert.ToChar(Console.ReadLine());
}
Well the simplest way would be to just use comparisons. If you definitely want to do it in a single expression, Glorfindel's answer is appropriate. However, all those brackets and the negation makes me nervous of the readability. I'd break it into a separate method:
while (!IsValidLetter(letter))
{
...
}
...
private static bool IsValidLetter(char letter)
{
return (letter >= 'a' && letter <= 'z') ||
(letter >= 'A' && letter <= 'Z');
}
Whichever you find more readable - the latter is easier to modify later, of course, if you end up with more complicated requirements.
Another option is to use a regular expression, like this:
while (!Regex.IsMatch(letter, "[a-zA-Z]"))
{
Console.WriteLine("Enter a letter please!");
letter = Console.ReadLine();
}
I create calculator which have buttons with numbers and operators for basic operation (+, -,...) and just want to filter buttons with numbers to detect when is clicked number (between 0-9). Also i put new eventhadler which convert sender to button.
I wondering what will be nice and easy way to filter the buttons with numbers (using linq)
What did i try so far is
if(btn.Text == btn.Text.Contains(x => x >= '0' && x <= '9'))
MessageBox.Show("number " + btn.Text + " is pressed!");
How to make upper code workable?
Here you go, for your immediate needs:
if(btn.Text.All(char.IsDigit))
{
//Do your stuff
}
If all you want to know is that is it a number or not do this. No LINQ is required
LINQ Way to check the numbers are between 0 and 9
if(yourstring.ToCharArray().Where(c=> c < '0' || c > '9').Any())
return false;
else
return true;
To check that it contains a valid number
double num;
if (double.TryParse(btn.Text, out num))
{
// It's a number!
}
or to check less than 10 without linq
static bool IsLessThanTen(string str)
{
foreach (char c in str)
{
if (c < '0' || c > '9')
return false;
}
return true;
}
if you need to check at least one number in the button text, then use below
return btn.Text.Any(char.IsDigit)
If you writing calculator, you better check NCalc - Mathematical Expressions Evaluator for .NET and this CodeProject tutorial
This should work
bool hasNumeric = yourString.IndexOfAny("0123456789".ToCharArray()) > -1;
I want to allow user to enter characters,numbers and special characters but no the JUNK Characters (ex. ♠ ♣ etc) whose ascii value is greater thane 127.
I have function like this
for (int i = 0; i < value.Length; i++) // value is input string
{
if ((int)value[i] < 32 || (int)value[i] > 126)
{
// show error
}
}
This makes code bit slower as i have to compare each and every string and its character.
Can anyone suggest better approach ?
Well, for one thing you can make the code simpler:
foreach (char c in value)
{
if (c < 32 || c > 126)
{
...
}
}
Or using LINQ, if you just need to know if any characters are non-ASCII:
bool bad = value.Any(c => c < 32 || c > 126);
... but fundamentally you're not going to be able to detect non-ASCII characters without iterating over every character in the string...
You can make regular expression which allowed all the desired characters and use it for each strings. I think this will improve the performance. All you have to do is to create a proper regular expression.
Update: However, Using RegEx will not improve the speed it will just minimize the code lines.