Regex Pattern number1 to number2 - c#

I'm searching for a pattern for the following behavior:
number1-number2
number1: Can be everything >= 0 and <= int.MaxValue
number2: Can be everything >= number1 and <= int.MaxValue
e.g.
"1-2" => True
"0-0" => True
"10-22" => True
"22-10" => False
"10-10" => True
"a-b" => False
It would be also nice if I could directly extract the two int values.

You cannot use a regex for comparing extracted numbers. You need to parse the values with int.TryParse and implement other checks to get what you need.
Assuming you only have integer positive numbers in the ranges, here is a String.Split and int.TryParse approach:
private bool CheckMyRange(string number_range, ref int n1, ref int n2)
{
var rng = number_range.Split('-');
if (rng.GetLength(0) != 2)
return false;
if (!int.TryParse(rng[0], out n1))
return false;
if (!int.TryParse(rng[1], out n2))
return false;
if (n1 >= 0 && n1 <= int.MaxValue)
if (n2 >= n1 && n2 <= int.MaxValue)
return true;
return false;
}
And call it like
int n1 = -1;
int n2 = -1;
bool result = CheckMyRange("1-2", ref n1, ref n2);

Solution
It is possible to test it using regex - but you should prefer a solution in code because it will be much faster. This regex needs a lot of backtracking. The only advantage of this regex is that it works for an arbitrary number length.
(?:^0+-\d+$)
|
(?:^(?>0*)(?<number>\d+)-(?>0*)\k<number>$)
|
(?:
(?:^(?>0*)(?<length>\d)+-(?>0*)(?<-length>\d)*(?(length)(?!))\d+$)
|
(
(?=^(?>0*)(?<o>\d)+-(?>0*)(?<-o>\d)*(?(o)(?!))$)
^
(?>0*)
(?<prefix>\d*)
(?:(?<g0>0)|(?<g1>1)|(?<g2>2)|(?<g3>3)|(?<g4>4)|(?<g5>5)|(?<g6>6)|(?<g7>7)|(?<g8>8)|(?<g9>9))
\d*
-
(?>0*)
\k<prefix>
(?(g0)[1-9]|(?(g1)[2-9]|(?(g2)[3-9]|(?(g3)[4-9]|(?(g4)[5-9]|(?(g5)[6-9]|(?(g6)[7-9]|(?(g7)[89]|(?(g8)9|(?!))))))))))
\d*
$
)
)
This matches for every x-y where x <= y for positive integer numbers including leeding zeros.
DEMO
It doesn't work for chars.
Explanation
I was able to create a regex that matches x-y for all x < y. The question was x <= y. So I splitted the question to x = y | x < y.
We need to handle that the first or both numbers does only contain zeros but that's trivial:
^0+-\d+$
Now the case x = y
^(?>0*)(?<number>\d+)-(?>0*)\k<number>$
The tricky part is x < y.
x is smaller than y if x is shorter in char length than y (leeding zeros are captured by an atomic group):
^(?>0*)(?<length>\d)+-(?>0*)(?<-length>\d)*(?(length)(?!))\d+
This first group captures the whole number by one capture per digit. After the separator a balancing group definition clears the capture stack and forces at least one more digit.
Both numbers are of the same length (if the first number is longer it is also greater and should not match).
To ensure that both numbers are of the same length I started with a positive look behind assertion that ensures it the same way I tested for a longer number in step 1:
(?=^(?>0*)(?<o>\d)+-(?>0*)(?<-o>\d)*(?(o)(?!))$)
After that the algorithm is simple. Start at the beginning. If the current digit is equal go to the next digit. If the current x-digit is slower than the current y-digit we're finished and a match is found. If it's slower we should not match. This is done by that pattern:
^
(?>0*) # cut out leeding zeros
(?<prefix>\d*)
.*
-
(?>0*) # cut out leeding zeros
\k<prefix> # both numbers start with the same part
.*
$
And now the check for one digit. There are only 10 possibilities [0-9]. Each of them is captures by a single group:
(?<g0>0)|(?<g1>1)|(?<g2>2)|(?<g3>3)|(?<g4>4)|(?<g5>5)|(?<g6>6)|(?<g7>7)|(?<g8>8)|(?<g9>9)
Now we're able to use conditions to check whether the current y-digit is greater then the current x-digit. Lets show for 0 and 1:
(?<g0>0)|(?<g1>1): If a 0 matches for the current x-digit there are only [1-9] for the current y-digit. If 1 matches only [2-9] is able. This could be used in a condition:
(?(g0)[1-9]|...) what means if g0 has a capture [1-9] has to match otherwise the rest has to match. This is combined to:
(?(g0)[1-9]|(?(g1)[2-9]|(?(g2)[3-9]|(?(g3)[4-9]|(?(g4)[5-9]|(?(g5)[6-9]|(?(g6)[7-9]|(?(g7)[89]|(?(g8)9|(?!))))))))))
The last trick is that none of the groups g[0-8] has been matched only g9 is available and there is no greater digit possible and the match should fail (?!).
This all has been combined to the whole regex that matches x-y for all x <= y.

Regex can only be used to match the numbers. Post that a comparison operation needs to be done.
string num="number1-number2";//where (number1 & number2)=numeric val
MatchCollection stringVal= Regex.Matches(num,#"\d+");
int num1=Convert.ToInt32(stringVal[0].Value);
int num2=Convert.ToInt32(stringVal[1].Value);
if(num1>=0 && num1<=int.MaxValue && num2>=num1 && num2<=int.MaxValue)
return true;
else
return false;
will give you an array containing the the numbers

Related

Generate all numbers of length M (1<M<10) with elements from {1,2,...N} with N(1<N<20)

thank you for taking the time to read this.
I'm working on a larger project that needs a function that generates all numbers based on the rules described in the title.
If inputs are M=3 and N=5 Outputs should be: 111,112,113,114,115,121....555
For inputs M=4 and N=2 Outputs should be: 1111,1112,1121...2222
I've been trying to make a function that does this for quite some time but i haven't succeeded. So I'm asking for help. I'm required to write it in C, but if you know how to fix it in C++ or C# I'll probably be able to translate it into C.
I don't have any code to show because thus far I've mostly tried brute-forcing it but it doesn't seem to work
Thank you for the help in advance!
If I understand the question, I would do it with regular expressions. This is all written with C in mind.
First build a regex with all the allowed digits. Posix provides a regex library (https://www.educative.io/edpresso/how-to-write-regular-expressions-in-c appears to be a good intro), so you only have to compose the string that will be parsed by regcomp() by iterating through the numbers from 1 to N. An appropriate regular expression would be, for N=20, ^(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20)+$. This will match strings composed entirely of any of those characters. (Since 0 should match only after 1 or 2 in this case, enumerating the options is simpler than trying to shorten the regex).
Then, iterate over the numbers starting with 10 ^ M and ending when you reach 10^(M+1). Write each number out as a string and see if it matches the regular expression - if it does, you have one of your results.
The problem can be boiled down to starting an M-digit, base-N number at its lowest value for the initial iteration, and incrementing it for subsequent iterations.
The M-digit number can be represented as an array (indexed from 0 to M-1) with one element per digit. One end of the array will hold the lowest order ("rightmost") digit and the other end of the array will hold the highest order ("leftmost") digit. It doesn't really matter which end is chosen to hold the highest order digit, so let's choose element 0 to hold the highest order digit. For generality, let's use digit values from 0 to N-1. (It doesn't really matter that the original problem has digits going from 1 to N since it is easy to map digit values from one scheme to the other.)
We can define a function to set the M-digit number to its lowest value:
void num_init(unsigned int *digits, unsigned int m)
{
while (m--)
{
digits[m] = 0;
}
}
We can define another function to increment the M-digit number and indicate whether the number has wrapped around back to its lowest value:
int num_inc(unsigned int *digits, unsigned int n, unsigned int m)
{
while (m--)
{
if (digits[m] < n - 1)
{
digits[m]++;
return 0;
}
digits[m] = 0; // carry
}
return 1;
}
Example usage:
// Print all M-digit numbers with digits from 1 to N.
void list_nums(unsigned int m, unsigned int n)
{
unsigned int digits[m];
int wrapped = 0;
num_init(digits, m);
while (!wrapped)
{
unsigned int i;
// output an m-digit number
for (i = 0; i < m; i++)
{
// Note: Add 1 to each digit so digits run from 1 to n instead of 0 to n-1.
printf("%u", digits[i] + 1);
}
// get next number
wrapped = num_inc(digits, n, m);
if (!wrapped)
{
printf(",");
}
}
printf("\n");
}
Note: The output of list_nums(m, n) will be strange when n is greater than 9.

trying to find the biggest negative and smallest positive from given input

im trying to build an algorythm which input is 10 numbers (positive and negative) and the output is the smallest positive number and the biggest negative number.
im getting the right answer for the smallest positive, but not for the biggest negative.
code and output are inserted.
If you have a collection, say, int[] numbers you can just query it with a help of Linq:
using System.Linq;
...
int[] numbers = ...
...
// Either biggest negative or 0 (if we don't have any negative values)
int biggestNegative = numbers
.Where(x => x < 0)
.DefaultIfEmpty() // <- we don't want exception on empty input
.Max();
// Either smallest positive or 0 (if we don't have any positive values)
int smallestPositive = numbers
.Where(x => x > 0)
.DefaultIfEmpty() // <- we don't want exception on empty input
.Min();
If you prefer to compute the values in a for loop:
int biggestNegative = 0;
int smallestPositive = 0;
for (int i = 0; i < 10; ++i) {
...
// Simplest, you may want to check user input
int value = int.Parse(Console.ReadLine());
...
if (value > 0)
smallestPositive = smallestPositive == 0
? value
: Math.Min(smallestPositive, value);
else if (value < 0)
biggestNegative = biggestNegative == 0
? value
: Math.Max(biggestNegativee, value);
}
Let's print the values out:
Console.WriteLine(
$"Biggest negative: {(biggestNegative == 0 ? "???" : biggestNegative.ToString())}");
Console.WriteLine(
$"Smallest positive: {(smallestPositive == 0 ? "???" : smallestPositive.ToString())}");
if (num>negMax)
There is a mistake in this condition. As your initial negMax value is 0, no negative number will meet the condition, and therefore negMax value will never be updated.
You're initializing negMax as 0.
There is no negative number that is bigger than 0.
Depending on what exactly you want to accomplish, you could do one of the following:
Initialize negMax as int.MinValue
This would be okay if it's guaranteed that there's at least one negative number, since the first negative input is guaranteed to be equal or greater. If negative input isn't guaranteed, you cannot tell if there were any and your output may end up incorrect.
Modify the condition for assigning a new value to negMax
You could instead modify the condition for assigning a new value to negMax to if (num > negMax || negMax >= 0).
Since you usually don't treat 0 as a negative number (and if you do, you can initialize negMax with any positive number instead), you'd know that there were no negative numbers if the output ends up as 0.
To do the same with posMin, you'd have to initialize it as something less than 0 and adjust the if-condition for assigning a value to that variable accordingly.
Alternatively, you could also declare negMax and posMin as int?s and check for null instead of >= 0.
If you choose this way, you can check the values for both variables and output, for example, that no negative or no positive numbers were entered instead of outputting whichever placeholder you chose.

c sharp finding a specific digit in an int [duplicate]

This question already has answers here:
Get the seventh digit from an integer
(9 answers)
Get individual digits from an Int without using strings?
(1 answer)
Closed 4 years ago.
I'm trying to find the nth digit of an integer (from right to left). I'm new to programming but have been using this site a lot for reference - up until now I've resisted passing my problems on but I cannot understand this one in the least, even after hours of effort.
This is the code I have so far but for FindDigit(int 5673, int 4) it gives 53 instead of 5, FindDigit(int 5673, int 3) gives 51 instead of 6
public class DigitFinder
{
public static int FindDigit(int num, int nth)
{
num = Math.Abs(num);
string answer = Convert.ToString(num);
int i = answer.Length;
return ans[i-nth];
}
}
I cannot understand at all why it returns a 2 digit number. Any guidance at all appreciated!
I'd just use
int result = (num / (int)Math.Pow(10,nth-1)) % 10;
Where num is the number to get the nth digit from (counted right to left) and nth is the "index" of digits you want (again: counted from right to left). Mind that it is 1-based. That is "1" is the rightmost digit. "0" would be out of range.
To explain the math:
(int)Math.Pow(10,nth-1) takes your desired index and decreases it by 1, then takes that as the power of 10. So if you want the 3rd digit, that makes 10 to the power of two equals 100.
BTW: the cast to int is necessary because Math.Pow works on double and returns double. But we want to keep on working in integer arithmetic.
Dividing by the result of above equation "shifts" your number to the right, so your desired digit becomes the rightmost digit. Example: 1234, we want 3rd digit from right ("2") => 1234 / (10^(3-1))= 1234 / 100 = 12
You then "cut out" that rightmost digit by applying the "remainder" (modulo) operator with divisor 10. Example: 12 % 10 = [12 / 10 = 1, Remainder =] 2.
Mind that I also would check nth to be > 0 and num >= 10 ^ (nth-1). (never trust user input)
53 is the ASCII code of the character 5. Just subtract the character 0, i.e. numeric 48.
However, it is usually a good idea to avoid string manipulation for things like this; if possible you should probably prefer division/remainder (modulo) arithmetic.
Just because no one else did, and also because i have Printable Character OCD
public static int GetLeastSignificantDigit(int number, int digit)
{
for (var i = 0; i < digit - 1; i++)
number /= 10;
return number % 10;
}
Demo here

how can I check if a string is a positive integer?

I mean :
1231 YES
121.1241 NO
121,1241 NO
-121 NO
124a NO
how can i do it faster in C#?
int x;
if (int.TryParse(str, out x) && x > 0)
You can check if it only contains digits:
if (theString.All(Char.IsDigit))
An alternative to actually parsing it is to check if the string is non-empty and only contains digits, optionally with a leading + sign if you want to allow that.
Note that this won't perform any range checking - so 9999999999999999999999999999999999 would be valid, even though it wouldn't fit into an int or a long.
You could use a regex for that, or possibly LINQ:
var nonNegative = text.Length > 0 && text.All(c => c >= '0' && c <= '9');
(This is similar to Guffa's Char.IsDigit approach, but restricts itself to ASCII digits. There are numerous non-ASCII digits in Unicode.)
Note that this will restrict it to non-negative values - not just positive values. How would you want to treat "0" and "0000"?

Return zero for negative integers

A friend just throw some code similar to following C# code:
int i = ...;
return i < 0 ? 0 : i;
That made me think. There's any "different" way to return zero for negative integers, or current positive value? More specifically I'm looking for bitwise operations, if possible.
BTW, I'm aware of Math.Max(0, i);
What's wrong with Math.Max?
You can do the equivalent without a branch using bitwise operations:
r = x ^ ((x ^ y) & -(x < y)); // == max(x, y)
If you substitute zero, it collapses to:
r = (y & -(0 < y)); // == max(0, y)
(Source: this list of bitwise tricks.)
If branches were extremely expensive on your platform, that might be worthwhile in some inner loop, I suppose, but it's pretty obscure and not the kind of thing I'd like to come across outside of an extremely time-sensitive function.
How about:
int i = ...;
return i & ~(i >> 31);
The below will do the trick and the code reads so well it practically don't need a comment ;)
((((0x80000000 & i) >> 31)^1) * 0xFFFFFFFF) & i
then again
int temp = (0x80000000 & i); //get the most significant bit (1 for negative 0 for positive)
temp = (temp>>31)^1; //more it to the least significant and not it (we now have 0 for negative numbers and one for positive)
temp *= 0xFFFFFFFF; //get a lof of F's if it's positive or a lot of zeros if the number was negative
temp = temp & i; //and the F's/zeros with the original number
and voila zero for all negative number and all positive are left unchanged
Short answer: No.
Bit operators do something very different, or rather are used for different problems.
If you know the size of your integers, you could test the highest (most significant) bit; if it's 1, the number is negative and you can act on that. But that would be a heck of a lot more work than the simple "<" test.
Not bitwise but different:
return (i + Math.abs(i))/2
EDIT:
return (int)(i/2f + Math.abs(i)/2f)

Categories

Resources