RegEx for ranges - c#

I want to be able to use a RegEx to parse out ranges like a Windows Print dialog (such as 1-50,100-110,111,112). The following is my current code and I am not clear on how to parse for the additional commas and numbers. I can parse out the hyphen, but not sure how to do it for additional commas or hyphens
private void tboxRowNum_Leave(object sender, EventArgs e)
{
Regex.Replace(tboxRowNum.Text, #"(?<first>\d+)-(?<last>\d+)",
new MatchEvaluator(this.parseSpaceDefinition));
}
private string parseSpaceDefinition(Match m)
{
int first = int.Parse(m.Groups["first"].Value);
int last = int.Parse(m.Groups["last"].Value);
StringBuilder sb = new StringBuilder(first.ToString());
for (int i = first + 1; i <= last; i++)
{
if (spaceItems == 0)
{
if (isNumeric(sb.ToString(), System.Globalization.NumberStyles.Integer))
{
startingSpace = Convert.ToInt32(sb.ToString());
}
}
sb.Append("," + i.ToString().Replace(" ", ""));
spaceItems++;
endingSpace = i;
}
tboxRowDesc.Text = sb.ToString();
return sb.ToString();
}
Edit 1: The modified code gets me what I want:
private void tboxRowNum_Leave(object sender, EventArgs e)
{
string[] parts = tboxRowNum.Text.Split(',');
for (int i = 0; i < parts.Length; i++)
{
if (parts[i].IndexOf('-') >= 0)
{
Regex.Replace(parts[i], #"(?<first>\d+)-(?<last>\d+)",
new MatchEvaluator(this.parseSpaceDefinition));
}
else
{
int number;
if(!(int.TryParse(parts[i], out number)))
{
MessageBox.Show("Incomplete/Invalid formula", "Invalid Space Definition");
tboxRowDesc.Text = "";
}
else
{
tboxRowDesc.Text += "," + number;
spaceItems++;
}
}
}
}

string[] ranges = inputString.split(',');
foreach (string rangeCandidate in ranges) {
// See if matches regex
}

Split it first on comma, and for each part check if it matches your regexp. If it does, do what you are already doing, otherwise just use int.Parse (or int.TryParse for robustness).

Related

How can I use indexof and substring to find words in a string?

In the constructor :
var tempFR = File.ReadAllText(file);
GetResults(tempFR);
Then :
private List<string> GetResults(string file)
{
List<string> results = new List<string>();
string word = textBox1.Text;
string[] words = word.Split(new string[] { ",," }, StringSplitOptions.None);
for(int i = 0; i < words.Length; i++)
{
int start = file.IndexOf(words[i], 0);
results.Add(file.Substring(start));
}
return results;
}
words contains in this case 3 words System , public , test
I want to find all the words in file and add them to the list results using indexof and substring.
The way it is now start value is -1 all the time.
To clear some things.
This is a screenshot of the textBox1 :
That is why I'm using two commas to split and get the words.
This screenshot showing the words after split them from the textBox1 :
And this is the file string content :
I want to add to the List results all the words in the file.
When looking at the last screenshot there should be 11 results.
Three time the word using three times the word system five times the word public.
but the variable start is -1
Update :
Tried Barns solution/s but for me it's not working good.
First the code that make a search and then loop over the files and reporting to backgroundworker :
int numberofdirs = 0;
void DirSearch(string rootDirectory, string filesExtension, string[] textToSearch, BackgroundWorker worker, DoWorkEventArgs e)
{
List<string> filePathList = new List<string>();
int numberoffiles = 0;
try
{
filePathList = SearchAccessibleFilesNoDistinct(rootDirectory, null, worker, e).ToList();
}
catch (Exception err)
{
}
label21.Invoke((MethodInvoker)delegate
{
label21.Text = "Phase 2: Searching in files";
});
MyProgress myp = new MyProgress();
myp.Report4 = filePathList.Count.ToString();
foreach (string file in filePathList)
{
try
{
var tempFR = File.ReadAllText(file);
_busy.WaitOne();
if (worker.CancellationPending == true)
{
e.Cancel = true;
return;
}
bool reportedFile = false;
for (int i = 0; i < textToSearch.Length; i++)
{
if (tempFR.IndexOf(textToSearch[i], StringComparison.InvariantCultureIgnoreCase) >= 0)
{
if (!reportedFile)
{
numberoffiles++;
myp.Report1 = file;
myp.Report2 = numberoffiles.ToString();
myp.Report3 = textToSearch[i];
myp.Report5 = FindWordsWithtRegex(tempFR, textToSearch);
backgroundWorker1.ReportProgress(0, myp);
reportedFile = true;
}
}
}
numberofdirs++;
label1.Invoke((MethodInvoker)delegate
{
label1.Text = string.Format("{0}/{1}", numberofdirs, myp.Report4);
label1.Visible = true;
});
}
catch (Exception err)
{
}
}
}
I have the words array already in textToSearch and the file content in tempFR then I'm using the first solution of Barns :
private List<string> FindWordsWithtRegex(string filecontent, string[] words)
{
var res = new List<string>();
foreach (var word in words)
{
Regex reg = new Regex(word);
var c = reg.Matches(filecontent);
int k = 0;
foreach (var g in c)
{
Console.WriteLine(g.ToString());
res.Add(g + ":" + k++);
}
}
Console.WriteLine("Results of FindWordsWithtRegex");
res.ForEach(f => Console.WriteLine(f));
Console.WriteLine();
return res;
}
But the results I'm getting in the List res is not the same output in Barns solution/s this is the results I'm getting the List res for the first file :
In this case two words system and using but it found only the using 3 times but there is also system 3 times in the file content. and the output format is not the same as in the Barns solutions :
Here is an alternative using Regex instead of using IndexOf. Note I have created my own string to parse, so my results will be a bit different.
EDIT
private List<string> FindWordsWithCountRegex(string filecontent, string[] words)
{
var res = new List<string>();
foreach (var word in words)
{
Regex reg = new Regex(word, RegexOptions.IgnoreCase);
var c = reg.Matches(filecontent).Count();
res.Add(word + ":" + c);
}
return res;
}
Simple change this part and use a single char typically a space not a comma:
string[] words = word.Split(' ');
int start = file.IndexOf(words[i],0);
start will be -1 if the word is not found.
MSDN: IndexOf(String, Int32)
for(int i = 0; i < words.Length; i++)
{
int start = file.IndexOf(words[i], 0);
// only add to results if word is found (index >= 0)
if (start >= 0) results.Add(file.Substring(start));
}
If you want all appearance of the words you need an extra loop
int fileLength = file.Length;
for(int i = 0; i < words.Length; i++)
{
int startIdx = 0;
while (startIdx < fileLength ){
int idx = file.IndexOf(words[i], startIdx]);
if (start >= 0) {
// add to results
results.Add(file.Substring(start));
// and let Word-search continue from last found Word Position Ending
startIdx = (start + words.Length);
}
}
int start = file.IndexOf(words[i], 0);
// only add to results if word is found (index >= 0)
if (start >= 0) results.Add(file.Substring(start));
}
MayBe you want a caseinsensitiv search
file.IndexOf(words[i], 0, StringComparison.CurrentCultureIgnoreCase); MSDN: StringComparer Class

How to count Specific words on RichTextbox

I have a program where i need to count how many females and Males are in the file that has been read into the richtextbox, but I'm not sure how to do that , in the file has the name, gender,specific job . I have to count between 15 different people
for example : " Donna,Female,Human Resources.",
This is what I have so far:
private void Form1_Load(object sender, EventArgs e)
{
StreamReader sr;
richTextBox1.Clear();
sr = new StreamReader("MOCK_DATA.txt");
string data;
while (!sr.EndOfStream)
{
data = sr.ReadLine();
richTextBox1.AppendText(data + "\n");
}
}
private void button1_Click(object sender, EventArgs e)
{
string[] data = richTextBox1.Text.Split(',');
for (int n = 0; n < data.Length; n++)
{
if (data[n] == richTextBox1.Text)
n++;
To get the plain text from a RichTextBox (stolen from this article):
string StringFromRichTextBox(RichTextBox rtb)
{
TextRange textRange = new TextRange(
// TextPointer to the start of content in the RichTextBox.
rtb.Document.ContentStart,
// TextPointer to the end of content in the RichTextBox.
rtb.Document.ContentEnd
);
// The Text property on a TextRange object returns a string
// representing the plain text content of the TextRange.
return textRange.Text;
}
Basic word counting routine:
int CountWord(string textToSearch, string word)
{
int count = 0;
int i = textToSearch.IndexOf(word);
while (i != -1)
{
count++;
i = textToSearch.IndexOf(word, i+1);
}
return count;
}
Putting it together:
var plainText = StringFromRichTextBox(richTextBox1);
var countOfMale = CountWord(plainText, "Male");
var countOfFemale = CountWord(plainText, "Female");
private void toolStripButton81_Click(object sender, EventArgs e)
{
string findterm = string.Empty;
findterm = toolStripTextBox2.Text;
// the search term - specific word
int loopCount = 0;
// count the number of instance
int findPos = 0;
// depending on checkbox settings
// whole word search or match case etc
try
{
while (findPos < GetRichTextBox().Text.Length)
{
if (wholeWordToolStripMenuItem.CheckState == CheckState.Checked & matchCaseToolStripMenuItem.CheckState == CheckState.Checked)
{
findPos = GetRichTextBox().Find(findterm, findPos, RichTextBoxFinds.WholeWord | RichTextBoxFinds.MatchCase);
}
else if (wholeWordToolStripMenuItem.CheckState == CheckState.Checked)
{
findPos = GetRichTextBox().Find(findterm, findPos, RichTextBoxFinds.WholeWord);
}
else if (matchCaseToolStripMenuItem.CheckState == CheckState.Checked)
{
findPos = GetRichTextBox().Find(findterm, findPos, RichTextBoxFinds.MatchCase);
}
else
{
findPos = GetRichTextBox().Find(findterm, findPos, RichTextBoxFinds.None);
}
GetRichTextBox().Select(findPos, toolStripTextBox2.Text.Length);
findPos += toolStripTextBox2.Text.Length + 1;
loopCount = loopCount + 1;
}
}
catch
{
findPos = 0;
}
// at the end bring the cursor at the beginning of the document
GetRichTextBox().SelectionStart = 0;
GetRichTextBox().SelectionLength = 0;
GetRichTextBox().ScrollToCaret();
// Show the output in statusbar
toolStripStatusLabel2.Text = "Instances: " + loopCount.ToString();
}

How to prevent text changing between special symbols

This code i used to text change as i need.
private void textBox1_TextChanged(object sender, EventArgs e)
{
string A = textBox1.Text.Trim();
A = A.Replace("A", "C");
A = A.Replace("F", "H");
A = A.Replace("C", "W");
A = A.Replace("B", "G");
textBox2.Text = (A);
}
Now i need to stop text changing after,
if i type '|' symbol in tetxbox1, Again i need to
start text changing if i type '|' symbol again,such as happened thing in this image.
So how can i prevent text changing between these two symbols only ||
You're replace code won't work how you have it, as it will just keep changing the characters for the same string(you change A to C, and later down you change C to W, so your final first character would be W and not C like you want).
Below is an overly complicated method(i also added a method that runs through each character of the string doing the replace) but it should work, and you can change as needed. Good luck
private void textBox1_TextChanged(object sender, EventArgs e)
{
string A = textBox1.Text.Trim();
string[] Aarry = A.Split('|');
string cleanedString = "";
for (int i = 0; i < Aarry.Length; i++)
{
if (i % 2 == 0)
cleanedString += FixText(Aarry[i]) + " ";
else
cleanedString += Aarry[i] + " ";
}
textBox2.Text = cleanedString ;
The method below will go through each character doing the replace
public string FixText(string A)
{
string newText = "";
for (int i = 0; i < A.Length; i++)
{
switch (A.Substring(i, 1))
{
case "A":
newText += A.Substring(i, 1).Replace("A", "C");
break;
case "F":
newText += A.Substring(i, 1).Replace("F", "H");
break;
case "C":
newText += A.Substring(i, 1).Replace("C", "W");
break;
case "B":
newText += A.Substring(i, 1).Replace("B", "G");
break;
default:
break;
}
}
return newText;
}
To handle the >500 lines of replacement type you have, you could setup a dictionary using method below:
public Dictionary<string, string> ReturnReplacementDictionary()
{
Dictionary<string, string> dictLibrary = new Dictionary<string,string)()
{
{"A","C"},
{"F","H"},
{"C","W"},
{"B","G"}
};
return dictLibrary;
}
In the above you would just continue adding in all your other replacement values.
Then you would call use that method below instead of the switch case(If you don't add a character/replacement to the dictionary method you can see it will just set the replacement character to blank):
public string FixTextUsingDictionary(string A)
{
Dictionary<string, string> replaceDict = ReturnReplacementDictionary();
string newText = "";
for (int i = 0; i < A.Length; i++)
{
string replacementLetter="";
if (replaceDict.TryGetValue(A.Substring(i, 1), out replacementLetter))
{
newText += replacementLetter;
}
// Added so that if the char is not in the dictionary the output will just have the original char
else { newText += A.Substring(i, 1); }
}
return newText;
}
Good luck
If the text is entered manually not pasted from clipboard, my solution will be:
int counter = 0;
private string replaceSpecial(string A)
{
if (A.Equals("A")) return "C";
else if (A.Equals("F")) return "H";
else if (A.Equals("C")) return "W";
else if (A.Equals("B")) return "G";
else if (A.Equals("|")) return "";
else return A;
}
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar.Equals('|'))
{
counter++;
}
if (counter == 0 || counter % 2 == 0)
textBox2.Text += replaceSpecial(e.KeyChar.ToString());
else
textBox2.Text += e.KeyChar.ToString().Replace("|", "");
}
considering that the only entered character is "|".
good luck
void StringReplace(string initialString)
{
bool insideSpecialCharacter = false;
string[] Pattern = { "A-C", "C-W", "F-H", "B-G" };
string specialCharacter = "|";
char[] characters = initialString.ToCharArray();
char?[] Newcharacters = new char?[characters.Length];
for (int i = 0; i < characters.Length; i++)
{
if (!characters[i].ToString().Equals(specialCharacter))
{
if (insideSpecialCharacter)
{
Newcharacters[i] = characters[i];
}
else
{
CheckPattern(Pattern, characters, Newcharacters, i);
}
}
else
{
insideSpecialCharacter = (insideSpecialCharacter) ? false : true;
}
}
txtSecond.Text = string.Concat(Newcharacters).Trim();
}
//-------Checks the Pattern Array and Replaces the Characters-----------
private static void CheckPattern(string[] Pattern, char[] characters, char?[] Newcharacters, int i)
{
for (int j = 0; j < Pattern.Length; j++)
{
string[] replaceValue = Pattern[j].Split('-');
if (characters[i].ToString() == replaceValue[0])
{
Newcharacters[i] = Convert.ToChar(characters[i].ToString().Replace(characters[i].ToString(), replaceValue[1]));
break;
}
else
{
Newcharacters[i] = characters[i];
}
}
}

Can't display method Word counter

I'm trying to create a method to pass a string to the method, and then I want to display the number of words in the string. The string being the user input from the textbox.
private void button1_Click(object sender, EventArgs e)
{
countMethod();
}
private string countMethod()
{
String text = textBox1.Text.Trim();
int wordCount = 0, index = 0;
while (index < text.Length)
{
// check if current char is part of a word
while (index < text.Length && Char.IsWhiteSpace(text[index]) == false)
index++;
wordCount++;
// skip whitespace until next word
while (index < text.Length && Char.IsWhiteSpace(text[index]) == true)
index++;
}
return MessageBox.Show(wordCount.ToString());
}
EDIT:
I added an argument to the method. And send the wordCount to a string, once the loop was done. I tried it several times and it works. I'm new to programming, and is there a reason why this wouldn't work or should do it another way? Thanks
private void button1_Click(object sender, EventArgs e)
{
string userInput = textBox1.Text;
countMethod(userInput);
}
private string countMethod(string input)
{
string text = textBox1.Text.Trim();
int wordCount = 0, index = 0;
while (index < text.Length)
{
// check if current char is part of a word
while (index < text.Length && Char.IsWhiteSpace(text[index]) == false)
index++;
wordCount++;
// skip whitespace until next word
while (index < text.Length && Char.IsWhiteSpace(text[index]) == true)
index++;
}
string total = wordCount.ToString();
MessageBox.Show("The total words in this string are: " +total);
return total;
}
There is an easier way to do it!
private void button1_Click(object sender, EventArgs e)
{
var wordCount = CountWords(textBox1.Text);
MessageBox.Show(wordCount.ToString());
}
private int CountWords(string input)
{
var separators = new[] { ' ', '.' };
var count = input.Split(separators, StringSplitOptions.RemoveEmptyEntries).Length;
return count;
}
Add/Remove the separators you want to/from the separators array.
Try to use extension method. It's good idea.
public static class MyExtentionClass
{
public static int WordCount(this string str)
{
var separators = new[] { ' ', '.', ',' };
var count = str.Split(separators, StringSplitOptions.RemoveEmptyEntries).Length;
return count;
}
}
eg:
MessageBox.Show(textBox1.Text.WordCount());
Split on white spaces then get the count
int wordCount = textBox1.Text.Trim().Split(" ").Count;

c# Add Specific columns from a TEXT file to DataGridView

Hello Everyone,
As shown in the above image I want to add the decimal numbers column wise from a text file to datagrid control.
Following is my code snippet
List<string> str = new List<string>();
String st = "";
int k = 0;
string[] s ;
//Path to write contents to text file
string filename = #"E:\Vivek\contentcopy\clientlist.txt";
Form.CheckForIllegalCrossThreadCalls = false;
OpenFileDialog ofd = new OpenFileDialog();
ofd.FileName = "";
ofd.ShowDialog();
st = ofd.FileName;
if (string.IsNullOrEmpty(ofd.FileName))
return;
string Name = "", No1 = "",No2="";
string[] lines = File.ReadAllLines(st).Where(sw => !string.IsNullOrWhiteSpace(sw)).ToArray();
for (int i = 0; i < lines.Length; i++)
{
if (lines[i].Contains("VENTURA SECURITIES LIMITED (NSE F&O)")) continue;
if (lines[i].Contains("ALL EXCHANGES DERIVATIVES CLIENTWISE STATEMENT AS ON 16-05-2012")) continue;
if (lines[i].Contains("-------------------------------------------------------")) continue;
s = lines[i].Split(' ');
if (s[0] == "PARTY" || s[0] == "") continue;
int z;
Name = "";
for (z = 1; z < s.Length; z++)
{
if (s[z] == "") continue;
if (s[z].Contains('.'))
{
No1+=s[z]+" ";
No2 = No1 + " ";
}
else
{
Name += s[z];
str.Add(s[0]+" "+Name);
}
}
dataGridView1.Rows.Add();
dataGridView1.Rows[k].Cells[0].Value = s[0];
dataGridView1.Rows[k].Cells[1].Value = Name;
dataGridView1.Rows[k].Cells[2].Value = No1;
dataGridView1.Rows[k].Cells[3].Value = No2;
k++;
}
File.WriteAllLines(filename, str);
dataGridView1.ReadOnly = true;
}
The line No1=s[z] directly takes the last column values ie 46,123.19 and so on.I want to fetch each column from the text file and store it in a string variable and then assign it to the datagrid view
I hope my doubt is clear.If not please let me know
Here is the simplest Solution:
Add a DataGrid View to Form and add a Button:
private void button1_Click(object sender, EventArgs e)
{
ReadAndFileter();
}
private void ReadAndFileter()
{
try
{
using(System.IO.StreamReader reader = new System.IO.StreamReader("file.txt"))
{
string line;
string []array;
int rowcount= 0;
decimal number;
string[] separators = { "\t", " " };
int columnCount = 0;
while ((line = reader.ReadLine()) != null)
{
array = line.Split(separators, StringSplitOptions.RemoveEmptyEntries);
dataGridView1.Rows.Add();
foreach (string str in array)
{
if (Decimal.TryParse(str,out number))
{
dataGridView1.Rows[rowcount].Cells[columnCount++].Value = number;
}
}
rowcount++;
columnCount = 0;
}
}
}
catch (Exception ex)
{
}
}
The File Contents are:
Abc 20.122 69.33 0.00 693.25 0.00
def 36.20 96.20 1.15 69.56 8.96
And the final output:
Lets say, you have for lines in your test file, then u need to do following things:
Use StreamReader.ReadLine(), to read one line at time.
Spilt the line using split(' ') and store it in a array
Remove all the empty ones from the array
Now at index 2,3,4,5,6 of the resulting array will have the string equivalent of the decimal numbers.
Repeat this for each StreamReader.ReadLine()
Hope this will help.
Your problem is that you are overwriting No1 every time you read a string, which explains why you only get the last value. What you could do is either;
Append the string:
No1 += s[z] + " ";
Which will put all the values behind eachother, seperated by a whitespace.
Or, you could make a List<String> and add each value to the list, meaning you have them stored seperated:
List<String> values = new List<String>();
foreach(...)
{
if (s[z] == "") continue;
if (s[z].Contains('.'))
{
values.Add(s[z])
}
else
{
Name += s[z];
str.Add(s[0] + " " + Name);
}
}
You can thereafter loop through the list and add each value to a row. Considering your code piece;
int i = 2;
foreach(string value in values)
{
dataGridView1.Rows[k].Cells[i].Value = value;
i++;
}
This should work.
Hope this helps.
Here is edited code: but for future I must suggest to give a try at least..
private void ReadAndFileter1()
{
try
{
using (System.IO.StreamReader reader = new System.IO.StreamReader("file.txt"))
{
string line;
string[] array;
int rowcount = 0;
decimal number;
string[] separators = { "\t", " " };
int columnCount = 1;
string[] lines = File.ReadAllLines("file.txt");
for (int i = 0; i < lines.Length; i++)
{
if (lines[i].Contains("VENTURA SECURITIES LIMITED (NSE F&O)")) continue;
if (lines[i].Contains("ALL EXCHANGES DERIVATIVES CLIENTWISE STATEMENT AS ON 16-05-2012")) continue;
if (lines[i].Contains("-------------------------------------------------------")) continue;
array = lines[i].Split(separators, StringSplitOptions.RemoveEmptyEntries);
if (array[0] == "PARTY" || array[0] == "") continue;
dataGridView1.Rows.Add();
foreach (string str in array)
{
if (Decimal.TryParse(str, out number))
{
dataGridView1.Rows[rowcount].Cells[columnCount++].Value = number;
}
}
dataGridView1.Rows[rowcount].Cells[0].Value = array[0];
rowcount++;
columnCount = 1;
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
Here it is:
static void Main(string[] args)
{
Decimal result;
string[] splitchar = new string[]{" "};
using(StreamReader reader = new StreamReader(#"C:\Users\Dell\Desktop\input.txt"))
{
while(!reader.EndOfStream)
{
string[] splittedArray = reader.ReadLine().Split(splitchar, StringSplitOptions.RemoveEmptyEntries).Where(x => Decimal.TryParse(x, out result)).ToArray();
// put your code here to get insert the values in datagrid
}
}
}

Categories

Resources