Deleting substrings "dynamically" from a line in C# - c#

I have a file with some lines in the text file like this
This is a test value with {MyTestValue = 0.34} How do I delete the test value? My line also has {MySecondTestValue = 0.35}
The value of MyTestValue is not the same value in each line.
Is there a way to determine the number of chars till the closing parenthesis and delete everything within the parentheses. So my output would be something like:
This is a test value with {} How do I delete the test value? My line also has {MySecondTestValue = 0.35}

Possible implementation via regular expressions:
String source = "This is a test value with {MyTestValue = 0.34} How do I delete the test value?";
String result = Regex.Replace(source, "{.*}", (MatchEvaluator) ((match) => "{}"));

string line="This is a test value with {MyTestValue = 0.34} How do I delete the test value?";
int index1=line.indexOf('{');
int index2=line.indexOf('}');
line=line.Replace(line.Substring(index1,index2-index1),"");

Try this
string output = Regex.Replace(input, #"{MyTestValue = [0-9.]+}", "{}");

Stringbuilder is the most efficient way to work with strings. You can create custom method that works with it :
static string[] ClearValues(string[] dirtyLines, string[] ignoreValuesList)
{
string[] result = new string[dirtyLines.Length];
bool ignore = false; StringBuilder s = new StringBuilder();
StringBuilder s2 = new StringBuilder();
for (int i = 0; i < dirtyLines.Length; i++)
{
for (int i2 = 0; i2 < dirtyLines[i].Length; i2++)
{
if (dirtyLines[i][i2] == '{') { s2.Clear(); s.Append(dirtyLines[i][i2]); ignore = true; continue; }
if (dirtyLines[i][i2] == '}') { if(ignoreValuesList.Contains(s2.ToString())) s.Append(s2.ToString()); s.Append(dirtyLines[i][i2]); ignore = false; continue; }
if (!ignore) { s.Append(dirtyLines[i][i2]); } else { s2.Append(dirtyLines[i][i2]); }
}
result[i] = s.ToString();
s.Clear();
}
return result;
}
Example of usage :
static void Main()
{
string[] dirtyLines =
{
"This is a test value with {MyTestValue = 0.34} How do I delete the test value?",
"This is {SomeOther = 11} How do I delete the test value?",
"{X = 134} How do {Y = 500} I delete the {Z = 400}test value?",
};
Stopwatch s = new Stopwatch();
s.Start();
string[] clean = ClearValues(dirtyLines, new[] { "Y = 500", "Z = 400" });
s.Stop();
for (int i = 0; i < clean.Length; i++)
{
Console.WriteLine(clean[i]);
}
Console.WriteLine("\nIt took {0} ms and {1} CPU ticks for method to execute", s.ElapsedMilliseconds, s.ElapsedTicks);
Console.ReadKey();
}
Output:

Related

Is there a way to compare two strings in C# and get the differences only?

I am trying to compare two string in C# and get the differences between them i.e words which are not present in the other string ignoring cases and commas just focusing on the words. If one string contains two or multiple the and the second string has one the, it means this will be disregarded as it exists in both. Example I have two strings like below;
Cat meet's a dog
Cat meet's a dog and a bird
The difference between those two strings is and bird because it does not exist in the first one or vise versa and I want to get those two words and bird either in a List or a new string with spaces between them and in other words I want the words which are not present in the other string. Is there a way this can be done in C#?
Here's a way using LINQ. You don't need the "ToList()" part, but you mentioned that as one form of output you'd want:
string str1 = "Cat meet's a dog";
string str2 = "Cat meet's a dog and a bird";
string[] str1Words = str1.ToLower().Split(' ');
string[] str2Words = str2.ToLower().Split(' ');
var uniqueWords = str2Words.Except(str1Words).Concat(str1Words.Except(str2Words)).ToList();
// Do whatever you want with uniqueWords instead
Console.WriteLine($"output: {String.Join(" ", uniqueWords)}");
#ngdeveloper. This is my variant of your solution (had to post it in a separate answer because of the length):
private static StringsDiff Difference(string firststring, string secondstring)
{
StringsDiff _stringsDiff = new StringsDiff();
char[] _firstStringArray = firststring.ToCharArray();
char[] _secondStringArray = secondstring.ToCharArray();
int shortestLenght;
int longestLenght;
bool firstIsLongest;
if (_firstStringArray.Length > _secondStringArray.Length)
{
firstIsLongest = true;
shortestLenght = _secondStringArray.Length;
longestLenght = _firstStringArray.Length;
}
else
{
firstIsLongest = false;
shortestLenght = _firstStringArray.Length;
longestLenght = _secondStringArray.Length;
}
for (int i = 0; i < shortestLenght; i++)
{
if (!_firstStringArray[i].Equals(_secondStringArray[i]))
{
_stringsDiff._diffList1.Add(_firstStringArray[i]);
_stringsDiff._diffList2.Add(_secondStringArray[i]);
}
}
for (int i = shortestLenght; i < longestLenght; i++)
{
if (firstIsLongest)
_stringsDiff._diffList1.Add(_firstStringArray[i]);
else
_stringsDiff._diffList2.Add(_secondStringArray[i]);
}
return _stringsDiff;
}
I wrote you a simple solution, hope it will help -
The main method is called 'Difference' it receive 2 strings to compare and return an object called StringDiff.
It runs 2 loops, first comparing between the two strings char by char and then adding the rest of the longer string.
The 'StringDiff' object is a class with 2 char lists that represnt the differences of each string.
In the main method i use String.join to convert the char lists to a string and print it.
internal class Program
{
static void Main(string[] args)
{
while (true)
{
Console.WriteLine("enter first string");
string firstString = Console.ReadLine();
Console.WriteLine("enter second string");
string secondString = Console.ReadLine();
StringsDiff _stringsDiff = Difference(firstString, secondString);
Console.WriteLine(
$"fist string difference: {string.Join("", _stringsDiff._diffList1)} / second string difference: {string.Join("", _stringsDiff._diffList2)}");
Console.WriteLine("/////////////////////////////////////");
}
}
private static StringsDiff Difference(string firststring, string secondstring)
{
StringsDiff _stringsDiff = new StringsDiff();
char[] _firstStringArray = firststring.ToCharArray();
char[] _secondStringArray = secondstring.ToCharArray();
int lenght;
if (_firstStringArray.Length > _secondStringArray.Length)
{
lenght = _secondStringArray.Length;
for (int i = 0; i < lenght; i++)
{
if (!_firstStringArray[i].Equals(_secondStringArray[i]))
{
_stringsDiff._diffList1.Add(_firstStringArray[i]);
_stringsDiff._diffList2.Add(_secondStringArray[i]);
}
}
for (int i = _secondStringArray.Length; i < _firstStringArray.Length; i++)
{
_stringsDiff._diffList1.Add(_firstStringArray[i]);
}
}
else
{
lenght = _firstStringArray.Length;
for (int i = 0; i < lenght; i++)
{
if (!_firstStringArray[i].Equals(_secondStringArray[i]))
{
_stringsDiff._diffList1.Add(_firstStringArray[i]);
_stringsDiff._diffList2.Add(_secondStringArray[i]);
}
}
for (int i = _firstStringArray.Length; i < _secondStringArray.Length; i++)
{
_stringsDiff._diffList2.Add(_secondStringArray[i]);
}
}
return _stringsDiff;
}
class StringsDiff
{
public List<char> _diffList1 = new List<char>();
public List<char> _diffList2 = new List<char>();
}
}
Remember to use "string.join" to connect the lists objects if you need a string.

List[i].Replace in for-loop won't return string

Trying to make hangman (i'm still a newbie) and the program chooses a random word out of a textfile ==> word turned into arrays. And i have to put it in a label while having the textlabel modified to what's in the letterlist. Thing is: it doesn't show anything in the label and i can't seem to figure out why.
So the for-loop is the modifier and when it has modified every string in the list it should return the word with the right letter or "_".
At first i tried is by doing: letterlist[i] = Letter or letterlist[i] = "_", but would happen is if i typed in a right letter it would show only that letter.
For example: word = "pen". If i typed in "p", it resulted in "ppp".
letterlist = new List<string>();
char[] wordarray = woord.GetWordcharArray(); //word in charArrays
string newwordstring = new string(wordarray);
for (int i = 0; i < wordarray.Length; i++)
{
letterlist.Add(" "); //adds empty strings in list with the length of the word
}
/*
* For-loop for every string in List to check and modify if it's correct or not
*/
for (int i = 0; i < letterlist.Count; i++)
{
if (letterlist[i].Contains(Letter) && newwordstring.Contains(Letter)) //right answer: letter[i] = Letter
{
letterlist[i].Replace(Letter, Letter);
}
else if (letterlist[i].Contains(" ") && newwordstring.Contains(Letter)) //right answer: letter[i] = ""
{
letterlist[i].Replace(" ", Letter);
}
else if (letterlist[i].Contains("_") && newwordstring.Contains(Letter)) //right answer: letter[i] = "_"
{
letterlist[i].Replace("_", Letter);
}
else if (letterlist[i].Contains(" ") && !newwordstring.Contains(Letter)) //wrong answer: letter[i] = ""
{
letterlist[i].Replace(" ", "_");
}
else if (letterlist[i].Contains("_") && !newwordstring.Contains(Letter)) //wrong answer: letter[i] = "_"
{
letterlist[i].Replace(" ", "_");
}
}
/*
* empty += every modified letterlist[i]-string
*/
string empty = "";
foreach (string letter in letterlist)
{
empty += letter;
}
return empty;
New code but it only shows "___" ("_" as many times as the amount of letters as word has):
char[] wordarray = woord.GetWordcharArray(); //word in charArrays
string newwordstring = new string(wordarray); //actual word
string GuessedWord = new string('_', newwordstring.Length);//word that shows in form
bool GuessLetter(char letterguess)
{
bool guessedright = false;
StringBuilder builder = new StringBuilder(GuessedWord);
for(int i = 0; i < GuessedWord.Length; i++)
{
if(char.ToLower(wordarray[i]) == Convert.ToChar(Letter))
{
builder[i] = wordarray[i];
guessedright = true;
}
}
GuessedWord = builder.ToString();
return guessedright;
}
return GuessedWord;
First of all, note that C# string are immutable, which means letterlist[i].Replace(" ", "_") does not replace spaces with underscores. It returns a new string in which spaces have been replaced with underscores.
Therefore, you should reassign this result:
letterlist[i] = letterlist[i].Replace(" ", "_");
Second, Replace(Letter, Letter) won't do much.
Third, in your first for loop, you set every item in letterlist to " ".
I don't understand then why you expect (in your second for loop) letterlist[i].Contains("_") to ever be true.
Finally, I'll leave here something you might find interesting (especially the use of StringBuilder):
class Hangman
{
static void Main()
{
Hangman item = new Hangman();
item.Init();
Console.WriteLine(item.Guessed); // ____
item.GuessLetter('t'); // true
Console.WriteLine(item.Guessed); // T__t
item.GuessLetter('a'); // false
Console.WriteLine(item.Guessed); // T__t
item.GuessLetter('e'); // true
Console.WriteLine(item.Guessed); // Te_t
}
string Word {get;set;}
string Guessed {get;set;}
void Init()
{
Word = "Test";
Guessed = new string('_',Word.Length);
}
bool GuessLetter(char letter)
{
bool guessed = false;
// use a stringbuilder so you can change any character
var sb = new StringBuilder(Guessed);
// for each character of Word, we check if it is the one we claimed
for(int i=0; i<Word.Length; i++)
{
// Let's put both characters to lower case so we can compare them right
if(Char.ToLower(Word[i]) == Char.ToLower(letter)) // have we found it?
{
// Yeah! So we put it in the stringbuilder at the same place
sb[i] = Word[i];
guessed = true;
}
}
// reassign the stringbuilder's representation to Guessed
Guessed = sb.ToString();
// tell if you guessed right
return guessed;
}
}

Efficiency in filling an array

I am coding an application that asks a user to enter a word, and then the program checks if there are any words contained within the larger word that are in the dictionary. For example, if the user entered "starburst", the system would output "star" and "burst".
I am creating my own dictionary of words within the program. So far I have an array, and I simply go one by one and add different words to the dictionary. Is there a more efficient way of doing this?
code posted below:
static void Main(string[] args) {
Console.WriteLine("Enter a word");
string word = Console.ReadLine();
string word2 = word;
string [] dictionary = new string[300];
dictionary[0] = "apple";
dictionary[1] = "adversary";
dictionary[2] = "apply";
dictionary[3] = "be";
dictionary[4] = "bear";
dictionary[5] = "Bare";
dictionary[6] = "car";
dictionary[7] = "care";
dictionary[8] = "cat";
dictionary[9] = "carreer";
dictionary[10] = "day";
dictionary[11] = "dare";
dictionary[12] = "date";
dictionary[13] = "do";
dictionary[14] = "double";
dictionary[15] = "ex";
dictionary[16] = "extra";
dictionary[17] = "can";
dictionary[18] = "dog";
dictionary[19] = "dont";
for (int i = 0; i < word.Length; i++)
{
for (int n = word2.Length; n < dictionary.Length; n++)
{
if (word == dictionary[n] && word != word2)
{
Console.WriteLine(word);
}
if(word2 == dictionary[n] && word != word2)
{
Console.WriteLine(word2);
}
word.Substring(1, word.Length - 1);
word2.Substring(0, word2.Length - 2);
}
}
}
Is there a more efficient way of doing this?
I assume you mean not having to manually change the array initialization code and recompile the application when you want to add a word to the dictionary.
You could do this by putting your word list in a file, and reading it with string [] dictionary = File.ReadAllLines("dictionary.txt").

C# StringBuilder: Check if it ends with a new line

I have a StringBuilder that accumulates code. In some cases, it has 2 empty lines between code blocks, and I'd like to make that 1 empty line.
How can I check if the current code already has an empty line at the end? (I prefer not to use its ToString() method because of performance issues.)
You can access any character of your StringBuilder with its index, like you would with a String.
var sb = new StringBuilder();
sb.Append("Hello world!\n");
Console.WriteLine(sb[sb.Length - 1] == '\n'); // True
You can normalize the newlines, using a regex:
var test = #"hello
moop
hello";
var regex = new Regex(#"(?:\r\n|[\r\n])+");
var newLinesNormalized = regex.Replace(test, Environment.NewLine);
output:
hello
moop
hello
Single line check. Uses a string type, not StringBuilder, but you should get the basic idea.
if (theString.Substring(theString.Length - Environment.NewLine.Length, Environment.NewLine.Length).Contains(Environment.NewLine))
{
//theString does end with a NewLine
}
else
{
//theString does NOT end with a NewLine
}
Here is the complete example.
class string_builder
{
string previousvalue = null;
StringBuilder sB;
public string_builder()
{
sB = new StringBuilder();
}
public void AppendToStringBuilder(string new_val)
{
if (previousvalue.EndsWith("\n") && !String.IsNullOrEmpty(previousvalue) )
{
sB.Append(new_val);
}
else
{
sB.AppendLine(new_val);
}
previousvalue = new_val;
}
}
class Program
{
public static void Main(string[] args)
{
string_builder sb = new string_builder();
sb.AppendToStringBuilder("this is line1\n");
sb.AppendToStringBuilder("this is line2");
sb.AppendToStringBuilder("\nthis is line3\n");
}
}
I've got 'funny' answer:
var sb = new StringBuilder();
sb.AppendLine("test");
sb.AppendLine("test2");
Console.WriteLine(sb.ToString().TrimEnd('\n').Length != sb.ToString().Length); //true
Since I don't care about 2 empty lines in the middle of the code, the simplest way is to use
myCode.Replace(string.Format("{0}{0}", Environment.NewLine),Environment.NewLine);
This option doesn't require any changes to classes that use the code accumulator.
In-case anyone ends up here like I did here is a general method to check the end of a StringBuilder for an arbitrary string with having to use ToString on it.
public static bool EndsWith(this StringBuilder haystack, string needle)
{
var needleLength = needle.Length - 1;
var haystackLength = haystack.Length - 1;
if (haystackLength < needleLength)
{
return false;
}
for (int i = 0; i < needleLength; i++)
{
if (haystack[haystackLength - i] != needle[needleLength - i])
{
return false;
}
}
return true;
}

Find all pattern indexes in string in C#

How can I find all indexes of a pattern in a string using c#?
For example I want to find all ## pattern indexes in a string like this 45##78$$#56$$JK01UU
string pattern = "##";
string sentence = "45##78$$#56$$J##K01UU";
IList<int> indeces = new List<int>();
foreach (Match match in Regex.Matches(sentence, pattern))
{
indeces.Add(match.Index);
}
indeces will have 2, 14
Edited the code to make it a cleaner function.
public IEnumerable<int> FindAllIndexes(string str, string pattern)
{
int prevIndex = -pattern.Length; // so we start at index 0
int index;
while((index = str.IndexOf(pattern, prevIndex + pattern.Length)) != -1)
{
prevIndex = index;
yield return index;
}
}
string str = "45##78$$#56$$JK01UU";
string pattern = "##";
var indexes = FindAllIndexes(str, pattern);
You can get all the indices of a pattern in a string by using a regex search like this.
string input = "45##78$$#56$$JK01UU", pattern = Regex.Escape("##");
Regex rx = new Regex(pattern);
var indices = new List<int>();
var matches = rx.Matches(s);
for (int i=0 ; i<matches.Length ; i++)
{
indices.Add(matches[i].Index);
}
Another one that tries to be efficient:
public IEnumerable<int> FindPatternIndexes(string input, string search)
{
var sb = new StringBuilder(input);
for (var i = 0; search.Length <= sb.Length; i++)
{
if (sb.ToString().StartsWith(search)) yield return i;
sb.Remove(0,1);
}
}
Tested. Worked. But somewhat dumb.
string foo = "45##78$$#56$$JK01UU";
char[] fooChar = foo.ToCharArray();
int i = 0;
bool register = false;
foreach (char fc in fooChar)
{
if (fc == '#' && register == true)
{
MessageBox.Show("Index: " + (i-1));
}
else if (fc == '#')
{
register = true;
}
else
{
register = false;
}
i++;
}

Categories

Resources