Split string at particular characters (C#) - c#

What I want to do is to split an array and then put the character which i split at into another element
i.e. string text = "1*5+89-43&99" should become string[] textsplit = ["1","*","5","+","89","-","43","&","99"] (it must be a string)
and I will supply the characters to be left in seperate elements

You can do this using string.IndexOfAny.
Simply keep looking for the next index of any of the separators. When you find a separator, add the text between it and the last separator to your results, then look for the next separator.
string input = "1*1*5+89-43&33";
var separators = new[] { '+', '-', '*', '/', '&' };
var result = new List<string>();
int index;
int lastIndex = 0;
while ((index = input.IndexOfAny(separators, lastIndex)) != -1)
{
// Add the text before the separator, if there is any
if (index - lastIndex > 0)
{
result.Add(input.Substring(lastIndex, index - lastIndex));
}
// Add the separator itself
result.Add(input[index].ToString());
lastIndex = index + 1;
}
// Add any text after the last separator
if (lastIndex < input.Length)
{
result.Add(input.Substring(lastIndex));
}

Try with the following code snippet:
string text = "1*1*5+89-43&33";
List<string> textsplit = new List<string>();
foreach(var match in Regex.Matches(text, #"([*+/\-)(])|([0-9]+)"))
{
textsplit.Add(match.ToString());
}
Result added as an image.

Here's a basic and naive implementation that I beliewe will do what you want:
public static List<string> SplitExpression(string expression)
{
var parts = new List<string>();
bool isNumber(char c) => c == '.' || (c >= '0' && c <= '9');
bool isOperator(char c) => !isNumber(c);
int index = 0;
while (index < expression.Length)
{
char c = expression[index];
index++;
if (isNumber(c))
{
int numberIndex = index - 1;
while (index < expression.Length && isNumber(expression[index]))
index++;
parts.Add(expression.Substring(numberIndex, index - numberIndex));
}
else
parts.Add(c.ToString());
}
// move unary signs into following number
index = 0;
while (index < parts.Count - 1)
{
bool isSign = parts[index] == "-" || parts[index] == "+";
bool isFirstOrFollowingOperator = index == 0 || isOperator(parts[index - 1][0]);
bool isPriorToNumber = isNumber(parts[index + 1][0]);
if (isSign && isFirstOrFollowingOperator && isPriorToNumber)
{
parts[index + 1] = parts[index] + parts[index + 1];
parts.RemoveAt(index);
}
else
index++;
}
return parts;
}
Example input: "-1+-2*-10.1*.1", and output:
-1
+
-2
*
-10.1
*
.1

Related

How to rearrange a string so no adjent letters are the same

I am trying to rearrange a given string, so no two adjacent letters are the same.
For that I'm thinking to count every distinct letter's occurence, and then rearrange the string the characters occurence number
example:
Input: AABAABBC
Output: AAAABBBC
and after that spliting it in 2 different strings
AAAA BBBC
and then trying to get the final result.
My question is how do I rearrange the string without using Linq?
Here is my code so far:
private static string GetDistinctChars(string text)
{
string result = "";
foreach (char c in text)
{
if (!result.Contains(c))
{
result += c;
}
}
return result;
}
private static double GetCharOccurrence(string text, char charToCount)
{
int count = 0;
foreach (char c in text)
{
if (c == charToCount)
{
count++;
}
}
return count;
}
You can do it like that:
string example = "AABBAACDCAA";
var orderList = example.OrderBy(x => x).ToList();
List<string> letters = new List<string>();
string temp = string.Empty;
for(int i = 0; i < orderList.Count; i++)
{
temp += orderList[i];
if (i + 1 == orderList.Count)
{
letters.Add(temp);
break;
}
if(orderList[i] != orderList[i + 1])
{
letters.Add(temp);
temp = string.Empty;
}
}
string result = String.Join(" ", letters);
Console.WriteLine(result);
If you don't want to use Linq Order by method, you should implement sorting algorithm like this:
static char[] SortArray(char[] array)
{
int length = array.Length;
char temp = array[0];
for (int i = 0; i < length; i++)
{
for (int j = i + 1; j < length; j++)
{
if (array[i] > array[j])
{
temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}
return array;
}
and use it in your program:
string example = "AABBAACDCAA";
var orderList = SortArray(example.ToCharArray());
List<string> letters = new List<string>();
string temp = string.Empty;
for(int i = 0; i < orderList.Length; i++)
{
temp += orderList[i];
if (i + 1 == orderList.Length)
{
letters.Add(temp);
break;
}
if(orderList[i] != orderList[i + 1])
{
letters.Add(temp);
temp = string.Empty;
}
}
string result = String.Join(" ", letters);
Console.WriteLine(result);
alternativly, if you don't want to use list anymore, you can operate only on strigns:
string example = "AABBAACDCAA";
var orderList = SortArray(example.ToCharArray());
string lettersString = string.Empty;
for (int i = 0; i < orderList.Length; i++)
{
lettersString += orderList[i];
if (i + 1 == orderList.Length)
break;
if (orderList[i] != orderList[i + 1])
lettersString += " ";
}
Console.WriteLine(lettersString);
You can find your problem on LeetCode, it's a problem #767.
My algorithm is
If we have too many of same characters, we can't solve the problem (e.g. "aaaaaabc")
If solution exists, we can sort characters aababc -> aaabbc and then take item by item from the beginning and from the center:
For instance:
aababc -> aaabbc (ordered by frequency: a appears 3 time, b - 2, c - 1)
then
aaabbc => ab
^ ^
take these
aaabbc => abab
^ ^
take these
aaabbc => ababac <- final answer
^ ^
take these
Code:
using System.Linq;
using System.Text;
...
public static string ReorganizeString(string s) {
int count = s.GroupBy(c => c).Max(g => g.Count());
// One of the item is too frequent, no solutions
if (count > (s.Length + 1) / 2)
return "";
string st = string.Concat(s
.GroupBy(c => c)
.OrderByDescending(g => g.Count())
.ThenBy(g => g.Key) // not required, just for aesthetic
.SelectMany(c => c));
StringBuilder sb = new StringBuilder(s.Length);
for (int i = 0; i < s.Length / 2; ++i) {
sb.Append(st[i]);
sb.Append(st[(st.Length + 1) / 2 + i]);
}
// Middle character
if (s.Length % 2 != 0)
sb.Append(st[st.Length / 2]);
return sb.ToString();
}
Demo:
string value = "AABAABBC";
Console.Write(ReorganizeString(value));
Output:
ABABABAC
Fiddle it yourself.
Edit: If StringBuilder (as well as System.Text) is really forbidden, we can use string, which, however, slows down the routine:
using System.Linq;
...
public static string ReorganizeString(string s) {
int count = s.GroupBy(c => c).Max(g => g.Count());
// One of the item is too frequent, no solutions
if (count > (s.Length + 1) / 2)
return "";
string st = string.Concat(s
.GroupBy(c => c)
.OrderByDescending(g => g.Count())
.ThenBy(g => g.Key) // not required, just for aesthetic
.SelectMany(c => c));
string result = "";
for (int i = 0; i < s.Length / 2; ++i) {
result += st[i];
result += st[(st.Length + 1) / 2 + i];
}
// Middle character
if (s.Length % 2 != 0)
result += st[st.Length / 2];
return result;
}

How can I get the values new.TITLE['kinds.of'].food

I am new to regex. I have this string
new.TITLE['kinds.of'].food
or
new.TITLE['deep thought'].food
I want to retrieve these tokens:
new, TITLE, kinds.of, food.
or (2nd example)
new, TITLE, deep thought, food.
I can't simply split it with '.' I need regex match to get the values.
How is it done?
When working with tokens a parser (FST - Finite State Machine in this case) should do:
private static IEnumerable<string> ParseIt(string value) {
int lastIndex = 0;
bool inApostroph = false;
for (int i = 0; i < value.Length; ++i) {
char ch = value[i];
if (ch == '\'') {
inApostroph = !inApostroph;
continue;
}
if (inApostroph)
continue;
if (ch == '.' || ch == ']' || ch == '[') {
if (i - lastIndex > 0) {
if (value[lastIndex] != '\'')
yield return value.Substring(lastIndex, i - lastIndex);
else {
string result = value.Substring(lastIndex, i - lastIndex).Replace("''", "'");
yield return result.Substring(1, result.Length - 2);
}
}
lastIndex = i + 1;
}
}
if (lastIndex < value.Length)
yield return value.Substring(lastIndex);
}
Tests:
string test1 = #"new.TITLE['kinds.of'].food";
string test2 = #"new.TITLE['deep thought'].food";
string[] result1 = ParseIt(test1).ToArray();
string[] result2 = ParseIt(test2).ToArray();
Console.WriteLine(string.Join(Environment.NewLine, result1));
Console.WriteLine(string.Join(Environment.NewLine, result2));
Outcome:
new
TITLE
kinds.of
food
new
TITLE
deep thought
food

Identifing number of character/digits/special character in string

I want to calculate the summary of string in terms of number of alphabets, digits and special character in C#. For example:
String abc123$% should have summary like A3D3S2 (which means 3 Alphabet, 3 Digits and 2 Special character)
a34=$# should have summary like A1D2S3 (which means 1 Alphabet, 2 Digits and 3 Special character)
a3b$s should have summary like A1D1A1S1A1 (which means 1 Alphabet, 1 Digits,1 Alphabet, 1 Special character,1 Alphabet)
Can anyone guide me how can write an algorithm which can perform the above task in a quick way? as I think if I search the string character by character, then it will take considerable amount of time. and I have a large dataset of strings.
This works:
static string GetSummary(string input)
{
var sb = new StringBuilder();
string prevMode = "";
string curMode = "";
int sameModeCount = 0;
for (int i = 0; i <= input.Length; ++i)
{
if (i < input.Length)
{
char c = input[i];
if ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z')
{
curMode = "A";
}
else if ('0' <= c && c <= '9')
{
curMode = "D";
}
else
{
curMode = "S";
}
}
else
{
curMode = "";
}
if (curMode != prevMode && prevMode != "")
{
sb.Append(prevMode);
sb.Append(sameModeCount);
sameModeCount = 0;
}
prevMode = curMode;
++sameModeCount;
}
return sb.ToString();
}
Test:
public static void Main()
{
Console.WriteLine(GetSummary("abc123$%"));
Console.WriteLine(GetSummary("a34=$#"));
Console.WriteLine(GetSummary("a3b$s"));
}
Results:
A3D3S2
A1D2S3
A1D1A1S1A1
With Linq, you can do like this :
string myinput = "abc123$%";
int letter =0 , digit = 0, specialCharacter = 0;
myinput.ToCharArray().ToList().ForEach(x =>
{
letter = Char.IsLetter(x) ? ++letter : letter;
digit = Char.IsDigit(x) ? ++digit : digit;
specialCharacter = !Char.IsLetterOrDigit(x) ?
++specialCharacter : specialCharacter;
});
string formattedVal = String.Format("A{0}D{1}S{2}", letter, digit,
specialCharacter);
You can directly use array in Linq ForEach without converting to list by :
Array.ForEach(myinput.ToCharArray(), x =>
{
letter = Char.IsLetter(x) ? ++letter : letter;
digit = Char.IsDigit(x) ? ++digit : digit;
specialCharacter = !Char.IsLetterOrDigit(x) ? ++specialCharacter : specialCharacter;
});
string formattedVal = String.Format("A{0}D{1}S{2}", letter, digit, specialCharacter);
This should work:
string s = "a3b$s";
char etype = 'X'; //current character's type
char etypeinit = 'X'; //tracker variable - holds type of last character
string str = "";
int count = 1;
foreach(char c in s)
{
//Use this block of conditionals to assign type for current character
if(char.IsLetter(c))
{
etype = 'A';
}
else if(char.IsDigit(c))
{
etype = 'D';
}
else
{
etype = 'S';
}
//This is a different type of character compared to the previous one
if(etypeinit != etype)
{
str += string.Format("{0}{1}",etype,count); //Build the string
count = 1; //Reset count
}
else
{
count++; //Increment because this is the same type as previous one
}
etypeinit = etype; //Set tracker variable to type of current character
}
Console.WriteLine(str);
Little late and little complex but able to produces all expected output as per given inputs in the question, please take a look:
string inputString = "abc123$%ab12";
var results = inputString.Select(x => char.IsLetter(x) ? 'A' :
char.IsDigit(x) ? 'D' : 'S');
StringBuilder outPutBuilder = new StringBuilder();
char previousChar = results.First();
int charCount = 0;
foreach (var item in results)
{
switch (item)
{
case 'A':
if (previousChar == 'A')
{
charCount++;
}
else
{
outPutBuilder.Append(previousChar.ToString() + charCount);
charCount = 1;
}
break;
case 'D':
if (previousChar == 'D')
charCount++;
else
{
outPutBuilder.Append(previousChar.ToString() + charCount);
charCount = 1;
}
break;
default:
if (previousChar == 'S')
charCount++;
else
{
outPutBuilder.Append(previousChar.ToString() + charCount);
charCount = 1;
}
break;
}
previousChar = item;
}
outPutBuilder.Append(previousChar.ToString() + charCount);
Working example
Use a FOR loop to go through each character. If the character is in the range of a-z or A-Z then it is an alphabet. If in the range of 0-9 then it is a digit else special character.
Code
string inputStr = "a3b$s";
string outputStr = string.Empty;
char firstChar = Convert.ToChar(inputStr.Substring(0, 1));
outputStr = char.IsLetter(firstChar) ? "A1" : char.IsDigit(firstChar) ? "D1" : "S1";
for (int i = 1; i < inputStr.Length; i++)
{
char nextChar = char.IsLetter(inputStr[i]) ? 'A' :
char.IsDigit(inputStr[i]) ? 'D' : 'S';
char prevChar = Convert.ToChar(outputStr.Substring(outputStr.Length - 2, 1));
if (nextChar == prevChar)
{
int lastDig = Convert.ToInt32(outputStr.Substring(outputStr.Length - 1, 1));
outputStr = outputStr.Substring(0, outputStr.Length - 1) +
(lastDig + 1).ToString();
}
else
outputStr += nextChar.ToString() + "1";
}
Console.WriteLine(outputStr.ToString());
Output
A1D1A1S1A1
Find demo here

c# finding characters between brackets

I can't get it to work,
I need to get a character ex : i [L]ove [B]asketball and [H]ockey
i would like to take the L, B and H out of this string and show them in a console writeline
without using regex
I though about finding the position of [ with an indexof and add + 1 to get the letter and then replace the [ with something else ex: [ into &
so i could do a foreach bracket in that string... but i don't think it'll work o.O
Console.WriteLine("Characters are : ");
foreach(Brackets in sentence)..
string str = " i [L]ove [B]asketball and [H]ockey";
string[] array = str.Split('[');
foreach (var item in array)
{
if(item.Contains(']'))
Console.WriteLine(item[0]);
}
and you will get:
L
B
H
This would work as long as you don't have unpaired square brackets and there is a character between those square brackets.
You can do this without the split:
string str = " i [L]ove [B]asketball and [H]ockey";
for (int i = 0; i < str.Length; i++)
{
if(str[i] == '[')
Console.WriteLine(str[1 + i++]);
}
Using LINQ:
string s = "i [L]ove [B]asketball and [H]ockey";
var chars = s.Where((c, i) => i > 0 && s[i - 1] == '[' &&
i < s.Length - 1 && s[i + 1] == ']');
Equivalently:
var chars = Enumerable.Range(1, s.Length - 2)
.Where(i => s[i - 1] == '[' && s[i + 1] == ']')
.Select(i => s[i]);
You can use this regex to get the values between the brakets:
string input = "I [L]ove [B]asketball and [H]ockey";
var regex = new Regex(#"\[.*?\]");
var matches = regex.Matches(input);
foreach (var match in matches)
{
var letter = Regex.Replace(match.ToString(), #"\[|\]", string.Empty);
Console.WriteLine(letter);
}
With regex:
string str = " i [L]ove [B]asketball and [H]ockey";
Match match = Regex.Match(str, #"\[(.*?)\]");
StringBuilder sb = new StringBuilder();
//iterate over all matches
do
{
sb.Append(match);
match = match.NextMatch();
}while(match.Success); //condition
//note: Dump() only works in linqpad. Use Console.WriteLine() instead
sb.Dump();
//without brackets:
sb.ToString().Split(new []{'[',']'}, StringSplitOptions.RemoveEmptyEntries).Dump();
I have come up with lengthy code but it works with all the cases
Try This:
static void Main()
{
string line = "i [L]ove [B]asketball and [H]ockey";
int count = 0;
char temp=' ';
string str="";
foreach (char ch in line)
{
if (ch == '[')
{
count++;
}
else if (count ==1)
{
count++;
temp=ch;
}
else if(count==2 && ch==']')
{
str+=temp;
count=0;
}
else
{
count = 0;
}
}
Console.WriteLine(str);
}

Determine the unique string from a repeating string in C#

I need to develop an efficient algorithm for determining the unique (repeated) string given a string with repeating content (and only repeating content)...
For example:
"AbcdAbcdAbcdAbcd" => "Abcd"
"Hello" => "Hello"
I'm having some trouble coming up with an algorithm that is fairly efficient; any input would be appreciated.
Clarification: I want the shortest string that, when repeated enough times, is equal to the total string.
private static string FindShortestRepeatingString(string value)
{
if (value == null) throw new ArgumentNullException("value", "The value paramter is null.");
for (int substringLength = 1; substringLength <= value.Length / 2; substringLength++)
if (IsRepeatingStringOfLength(value, substringLength))
return value.Substring(0, substringLength);
return value;
}
private static bool IsRepeatingStringOfLength(string value, int substringLength)
{
if (value.Length % substringLength != 0)
return false;
int instanceCount = value.Length / substringLength;
for (int characterCounter = 0; characterCounter < substringLength; characterCounter++)
{
char currentChar = value[characterCounter];
for (int instanceCounter = 1; instanceCounter < instanceCount; instanceCounter++)
if (value[instanceCounter * substringLength + characterCounter] != currentChar)
return false;
}
return true;
}
Maybe this can work:
static string FindShortestSubstringPeriod(string input)
{
if (string.IsNullOrEmpty(input))
return input;
for (int length = 1; length <= input.Length / 2; ++length)
{
int remainder;
int repetitions = Math.DivRem(input.Length, length, out remainder);
if (remainder != 0)
continue;
string candidate = input.Remove(length);
if (String.Concat(Enumerable.Repeat(candidate, repetitions)) == input)
return candidate;
}
return input;
}
Something like this:
public string ShortestRepeating(string str)
{
for(int len = 1; len <= str.Length/2; len++)
{
if (str.Length % len == 0)
{
sub = str.SubString(0, len);
StringBuilder builder = new StringBuilder(str.Length)
while(builder.Length < str.Length)
builder.Append(sub);
if(str == builder.ToString())
return sub;
}
}
return str;
}
This just starts looking at sub strings starting at the beginning and then repeats them to see if they match. It also skips any that do not have a length that doesn't evenly divide into the original strings length and only goes up to the length / 2 since anything over that cannot be a candidate for repeating.
I'd go with something like this:
private static string FindRepeat(string str)
{
var lengths = Enumerable.Range(1, str.Length - 1)
.Where(len => str.Length % len == 0);
foreach (int len in lengths)
{
bool matched = true;
for (int index = 0; matched && index < str.Length; index += len)
{
for (int i = index; i < index + len; ++i)
{
if (str[i - index] != str[i])
{
matched = false;
break;
}
}
}
if (matched)
return str.Substring(0, len);
}
return str;
}
Try this regular expression:
^(\w*?)\1*$
It captures as few characters as possible where the captured sequence (and only the captured sequence) repeat 0 or more times. You can get the text of the shortest match from the capture afterwards, as per Jacob's answer.
You could use a regular expression with back-references.
Match match = Regex.Match(#"^(.*?)\0*$");
String smallestRepeat = match.Groups[0];

Categories

Resources