regex to match comma delimited balanced square brackets having recursion - c#

I'd like a regex to match comma-delimited, balanced square brackets where the contents of the square brackets might be comma-delimited balanced square brackets themselves.
Here are some examples:
example 1
input = "[abc],[def]"
groups
group 1 = "abc"
group 2 = "def"
example 2
input = "[[ghi],[jkl]],[mno[pqr]],[[stu]]"
groups
group 1 = "[ghi],[jkl]"
group 2 = "mno[pqr]"
group 3 = "[stu]"
So note that in the second example, "ghi" and "jkl" are not their own groups. I don't need to recurse all the way down, I just need a regex to find the "level 0" groups.

Here's some code that can get you started on how to parse those values out.
public static IEnumerable<string> SplitSquareBraketByComma(string input)
{
int start = 0;
int brakets = 0;
for(int i = 0; i < input.Length; i++)
{
if(input[i] == '[')
{
brakets++;
continue;
}
if(input[i] == ']')
{
brakets--;
continue;
}
if(brakets == 0 && input[i] == ',')
{
yield return input.Substring(start, i - start);
start = i + 1;
}
}
if(start < input.Length)
{
yield return input.Substring(start);
}
}
It basically keeps count of the brackets and when it sees a comma when the number of open brackets is zero it splits out a new string from the previous split.
Note: this does not have any code to check that the input is valid (having all balanced brackets) and thus it's leaving in the outer most brackets just in case.

Related

Obtain the lexicographically smallest string possible, by using at most P points

⦁ Replace and/or re-arrange characters of this given string to get the lexicographically smallest string possible. For this, you can perform the following two operations any number of times.
⦁ Swap any two characters in the string. This operation costs 1 point. (any two, need not be adjacent)
⦁ Replace a character in the string with any other lower case English letter. This operation costs 2 points.
Obtain the lexicographically smallest string possible, by using at most P points.
Input:
⦁ Two lines of input, first-line containing two integers N, P.
⦁ The second line contains a string S consisting of N characters.
Output:
Lexicographically smallest string obtained.
for e.g
Sample Input:
3 3
bba
Sample Output:
aab
Ive tried this but it doesnt contain P points i dont know how to do that can you guys please help me with that:
namespace Lexicographical
{
class GFG
{
// Function to return the lexicographically
// smallest String that can be formed by
// swapping at most one character.
// The characters might not necessarily
// be adjacent.
static String findSmallest(char[] s)
{
int len = s.Length;
// Store last occurrence of every character
int[] loccur = new int[26];
// Set -1 as default for every character.
for (int i = 0; i < 26; i++)
loccur[i] = -1;
for (int i = len - 1; i >= 0; --i)
{
// char index to fill
// in the last occurrence array
int chI = s[i] - 'a';
if (loccur[chI] == -1)
{
// If this is true then this
// character is being visited
// for the first time from the last
// Thus last occurrence of this
// character is stored in this index
loccur[chI] = i;
}
}
char[] sorted_s = s;
Array.Sort(sorted_s);
for (int i = 0; i < len; ++i)
{
if (s[i] != sorted_s[i])
{
// char to replace
int chI = sorted_s[i] - 'a';
// Find the last occurrence
// of this character.
int last_occ = loccur[chI];
// Swap this with the last occurrence
char temp = s[last_occ];
s[last_occ] = s[i];
s[i] = temp;
break;
}
}
return String.Join("", s);
}
// Driver code
public static void Main(String[] args)
{
String s = "abb";
Console.Write(findSmallest(s.ToCharArray()));
}
}
}
The output for this is abb but it should be aab...
I want to know how i can use above Question in this

How to slice string on substrings that contain n characters c#?

The function gets a string of numbers (e.g. "23559009") and the length of substrings value (e.g. 2), I need to implement the function so that it will slice the string of numbers by the value (e.g. "23", "35", "55", "59", "90", "00", "09") AND will return this data as array.
For now I have initial code for tests:
using System;
public static class Series
{
public static string[] Slices(string numbers, int sliceLength)
{
int digits = numbers.Length;
if(digits != null || digits > sliceLength || sliceLength < 1)
throw new ArgumentException();
else
{
string[] dgts = {"1", "2"};
return dgts;
}
}
}
Using Linq:
public static string[] Slices(string numbers, int sliceLength) =>
Enumerable.Range(0, numbers.Length - sliceLength + 1).
Select(i => numbers.Substring(i, sliceLength)).
ToArray();
Note that the single character last entry will be ignored + you may want to validate the parameters (numbers not null and sliceLength > 0).
Fiddle
substring code for this will have major redundancy. send the string to a char array, then do a loop
char[] charray = inputstring.toCharArray();
List<string> deuces= new List<string>();
for(int i=0;i<charray.length;i++){
string holder = charray[i]+charray[i+1];
deuces.Add(holder)
}
keep in mind this is pseudo, everything you need is here, you will just have to create the variables, and make sure syntax is correct.
in the line : for(int i=0;i
the two represents the value you want to slice by,
in the line : string holder = charray[i]+charray[i+1];
you will need to add another char, for the amount of your split. i.e 3 would be:
string holder = charray[i].toString()+charray[i+1].toString+charray[i+2];
keep in mind if your split value ( in your case two) changes regularly you can nest another for loop
You have some errors in your evaluation of incorrect inputs, then getting your result in using normal for loop isn't difficult
public string[] Slices(string numbers, int sliceLength)
{
int digits = numbers.Length;
string[] result = new string[numbers.Length + 1 - sliceLength];
if (digits < sliceLength || sliceLength < 1)
throw new ArgumentException();
else
{
for(int x = 0; x < numbers.Length + 1 - sliceLength; x++)
result[x] = numbers.Substring(x, sliceLength);
return result;
}
}

Count the number of contiguous equal characters

I need to validate Serial numbers and one of the rules is that there are up to 5 contiguous equal characters allowed.
Example valid:
012W212222123 // 4x the digit 2 contiguous
Example invalid:
012W764444443 // 6x the digit 4
So I tried to get the maximum number of contiguous characters without success
int maxCount = "012W764444443".GroupBy(x => x).Max().Count();
I suggest using a regex for a check to see if there are 5 or more consecutive digits:
Regex.IsMatch(input, #"^(?!.*([0-9])\1{4})")
If any characters are meant:
Regex.IsMatch(input, #"^(?!.*(.)\1{4})")
See the regex demo
The regex finds a match in a string that contains less than 5 identical consecutive digits (version with [0-9]) or any characters other than a newline (version with .).
Details:
^ - start of string
-(?!.*(.)\1{4}) - a negative lookahead that fails the match if the pattern is matched:
.* - any 0+ chars other than a newline
(.) - Group 1 capturing any char but a newline
\1{4} - exactly 4 consecutive occurrences of the same value stored inside Group 1 (where \1 is a backreference and the {4} is a range/bound/limiting quantifier).
C#:
var strs = new List<string> { "012W212222123", "012W764444443"};
foreach (var s in strs)
Console.WriteLine("{0}: {1}", s, Regex.IsMatch(s, #"^(?!.*(.)\1{4})"));
Yet another option is to use this function:
public static int MaxNumberOfConsecutiveCharacters(string s)
{
if (s == null) throw new ArgumentNullException(nameof(s));
if (s.Length == 0) return 0;
int maxCount = 1;
int count = 1;
for (int i = 1; i < s.Length; i++)
{
if (s[i] == s[i-1])
{
count++;
if (count > maxCount) maxCount = count;
}
else
{
count = 1;
}
}
return maxCount;
}
Obviously, this is a lot more code than a regular expression. Depending on your knowledge of regular expressions, this may or may not be more readable to you. Also, this is probably more efficient than using a regular expression, which may or may not be important to you.
It's a little inefficient, but this works:
var max =
"012W212222123"
.Aggregate(
new { Char = ' ', Count = 0, Max = 0 },
(a, c) =>
a.Char == c
? new { Char = c, Count = a.Count + 1, Max = a.Max > a.Count + 1 ? a.Max : a.Count + 1 }
: new { Char = c, Count = 1, Max = a.Max > 1 ? a.Max : 1 })
.Max;
I tried with both inputs and got the right number of maximum repeats each time.

Regex to not match consecutive numbers in a string c#

My requirement is to enforce a password policy which contains a rule to not have consecutive numbers i.e. "pass1234","abc12","12tab" etc. should be not allowed. my current regex is:
if(!Regex.IsMatch(password,
#"^(?!(?:0(?=1)|1(?=2)|2(?=3)|3(?=4)|4(?=5)|5(?=6)|6(?=7)|7(?=8)|8(?=9)|9(?=0))\d{1,}|(?:0(?=9)|1(?=0)|2(?=1)|3(?=2)|4(?=3)|5(?=4)|6(?=5)|7(?=6)|8(?=7)|9(?=8))\d{1,})[a-zA-Z\d]+$")))
But the above regex matches strings that start with numbers i.e. "12abc", "12pass" but not the strings that contain numbers in between the string like "ab12pass","pass1234" etc.
Here's how I would do it without using regular expressions if you really meant you don't want consecutive increasing or decreasing numbers.
private static bool NoConsecutiveIncreasingOrDecreasingNumbers(string str)
{
if (string.IsNullOrWhiteSpace(str))
return true;
char prev = str[0];
for (int i = 1; i < str.Length; i++)
{
char current = str[i];
if ('0' < current && current < '9' &&
'0' < prev && prev < '9' &&
(prev + 1 == current || current + 1 == prev ))
return false;
prev = current;
}
return true;
}
Just remove that last condition in the if if you really did mean any consecutive numbers.
Here is a Regex to detect if there are ascending or descending numbers.
^((?:0(?=1|$))?(?:1(?=2|$))?(?:2(?=3|$))?(?:3(?=4|$))?(?:4(?=5|$))?(?:5(?=6|$))?(?:6(?=7|$))?(?:7(?=8|$))?(?:8(?=9|$))?9?|(?:9(?=8|$))?(?:8(?=7|$))?(?:7(?=6|$))?(?:6(?=5|$))?(?:5(?=4|$))?(?:4(?=3|$))?(?:3(?=2|$))?(?:2(?=1|$))?(?:1(?=0|$))?0?)$
Debuggex Demo

Count consequitive numbers in a string C#

I have a string {101110111010001111} I'm searching for the total number of all sequences of equal bits with an exact length of 3 bits. In above string the answer willbe 3 (please note that the last one "1111" doesn't count as it has more than 3 equal bits.
Any suggestions how to do this?
If you don't want a simple solution, try this:
string s = "1101110111010001111";
var regex = new Regex(#"(.)\1+");
var matches = regex.Matches(s);
int count = matches.Cast<Match>().Where(x => x.Length == 3).Count();
Explanation:
The regex finds sets of 2 or more identical characters (not limited to 0's and 1's)
Then only sets of exactly 3 characters are counted
Is it that you need? Sometimes the simplest solutions are the best:
public static int Count(string txt)
{
// TODO validation etc
var result = 0;
char lstChr = txt[0];
int lastChrCnt = 1;
for (var i = 1; i < txt.Length; i++)
{
if (txt[i] == lstChr)
{
lastChrCnt += 1;
}
else
{
if (lastChrCnt == 3)
{
result += 1;
}
lstChr = txt[i];
lastChrCnt = 1;
}
}
return lastChrCnt == 3 ? result + 1 : result;
}
You can use a regular expression:
Regex.Matches(s, #"((?<=0)|^)111((?=0)|$)|((?<=1)|^)000((?=1)|$)");
Here's the same expression with comments:
Regex.Matches(s, #"
(
(?<=0) # is preceeded by a 0
| # or
^ # is at start
)
111 # 3 1's
(
(?=0) # is followed by a 0
| # or
$ # is at start
)
| # - or -
(
(?<=1) # is preceeded by a 1
| # or
^ # is at start
)
000 # 3 0's
(
(?=1) # followed by a 1
| # or
$ # is at end
)", RegexOptions.IgnorePatternWhitespace).Dump();
You can split the string by "111" to get an array. You can then simply count the lines that not begins with "1" with the linq.
See the sample:
using System;
using System.Linq;
namespace experiment
{
class Program
{
static void Main(string[] args)
{
string data = "{101110111010001111}";
string[] sequences = data.Split(new string[] {"111"}, StringSplitOptions.None);
int validCounts = sequences.Count(i => i.Substring(0, 1) != "1");
Console.WriteLine("Count of sequences: {0}", validCounts);
// See the splited array
foreach (string item in sequences) {
Console.WriteLine(item);
}
Console.ReadKey();
}
}
}
Yet another approach: Since you are only counting bits, you can split the string by "1" and "0" and then count all elements with lenght 3:
string inputstring = "101110111010001111";
string[] str1 = inputstring.Split('0');
string[] str2 = inputstring.Split('1');
int result = str1.Where(s => s.Length == 3).Count() + str2.Where(s => s.Length == 3).Count();
return result
An algorithmic solution. Checks for any n consecutive characters. But this is not completely tested for all negative scenarios.
public static int GetConsecutiveCharacterCount(this string input, int n)
{
// Does not contain expected number of characters
if (input.Length < n || n < 1)
return 0;
return Enumerable.Range(0, input.Length - (n - 1)) // Last n-1 characters will be covered in the last but one iteration.
.Where(x => Enumerable.Range(x, n).All(y => input[x] == input[y]) && // Check whether n consecutive characters match
((x - 1) > -1 ? input[x] != input[x - 1] : true) && // Compare the previous character where applicable
((x + n) < input.Length ? input[x] != input[x + n] : true) // Compare the next character where applicable
)
.Count();
}

Categories