C# -> Repeaters and Displaying them with Loops through Arrays - c#

My question is part curiosity and part help, so bear with me.
My previous question had to do with passing text files as an argument to a function, which I managed to figure out with help, so thank you to all who helped previously.
So, consider this code bit:
protected bool FindWordInFile(StreamReader wordlist, string word_to_find)
{
// Read the first line.
string line = wordlist.ReadLine();
while (line != null)
{
if(line.Contains(word_to_find))
{
return true;
}
// Read the next line.
line = wordlist.ReadLine();
}
return false;
}
What happens with this particular function if you call in it the following way:
temp_sentence_string = post_words[i]; //Takes the first string in the array FROM the array and binds it to a temporary string variable
WordCount.Text = WordCount.Text + " ||| " + temp_sentence_string;
word_count = temp_sentence_string.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
for (int word_pos = 0; word_pos < word_count.Length; word_pos++)
{
bool WhatEver = FindWordInFile(goodwords_string, word_count[word_pos]);
if (WhatEver == true)
{
WordTest.Text = WordTest.Text + "{" + WhatEver + "} ";
}
WordTest.Text = WordTest.Text + "{" + WhatEver + "}";
}
AND:
The string passed is "good times are good" and the text file has the word "good" in it is this:
good{True}times{False}are{False}good{False}
Pretty strange. It looks like what happened is that:
1. The sentence "good times are good" got put into an array, split by the detection of a space. This happened correctly.
2. The first array element, "good" was compared against the text file and returned True. So that worked.
3. It then went to the next word "times", compared it, came up False.
4. Went to the next word "are", compared it, came up False.
5. THEN it got to the final word, "good", BUT it evaluated to False. This should NOT have happened.
So, my question is - what happened? It looks like the function of FindWordInFile was perhaps not coded right on my end, and somehow it kept returning False even though the word "good" was in the text file.
Second Part: Repeaters in ASP.NET and C#
So I have a repeater object bound to an array that is INSIDE a for loop. This particular algorithm takes an array of sentences and then breaks them down into a temp array of words. The temp array of words is bound to the Repeater.
But what happens is, let's say I have two sentences to do stuff to...
And so it's inside a loop. It does the stuff to the first array of words, and then does it to the second array of words, but what happens in the displaying the contents of the array, it only shows the contents of the LAST array that was generated and populated. Even though it's in the for loop, my expectation was that it would show all the word arrays, one after the other. But it only shows the last one. So if there's 5 sentences to break up, it only shows the 5th sentence that was populated by words.
Any ideas why?
for (int i = 0; i < num_sentences; i++) //num_sentences is an int that counted the number of elements in the array of sentences that was populated before. It populates the array by splitting based on punctuation.
{
temp_sentence_string = post_words[i]; //Takes the first string in the array FROM the sentence array and binds it to a temporary string variable
WordCount.Text = WordCount.Text + " ||| " + temp_sentence_string;
word_count = temp_sentence_string.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); //create a word count array with one word as a singular element in the array
//We have the Word Count Array now. We can go through it with a loop, right?
for (int j = 0; j < word_count.Length; j++)
{
Boolean FoundIt = File
.ReadLines(#"c:\wordfilelib\goodwords.txt") // <- Your file name
.Any(line => line.Contains(word_count[j]));
WordTest.Text = WordTest.Text + FoundIt + "(" + word_count[j] + ")";
}
Repeater2.DataSource = word_count;
Repeater2.DataBind();
}

First Part
You are passing a StreamReader into the Find function. A StreamReader must be reset in order to be used multiple times. Test with the following sentence and you will see the result.
"good good good good"
you will get
good{true}good{false}good{false}good{false}
I would suggest reading the file into an array only one time and then do your processing over the array.
using System.Linq
using System.Collections.Generic;
public class WordFinder
{
private static bool FindWordInLines(string word_to_find, string[] lines)
{
foreach(var line in lines)
{
if(line.Contains(word_to_find)
return true;
}
return false;
}
public string SearchForWordsInFile(string path, string sentence)
{
// https://msdn.microsoft.com/en-us/library/s2tte0y1(v=vs.110).aspx
var lines = System.IO.File.ReadAllLines(path);
var words = sentence.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
var result = string.Empty;
foreach(var word in words)
{
var found = FindWordInLines(word, lines);
// {{ in string.Format outputs {
// }} in string.Format outputs }
// {0} says use first parameter's ToString() method
result += string.Format("{{{0}}}", found);
}
return result;
}
}
Second Part:
If you bind it in the for loop like that it will only bind to the last result. If you accumulate the results in the outer loop you can pass the accumulated results to the repeater and bind outside the loop.
I created a sample loop class below that has two loops. The "resultList" is the variable that accumulates the results.
using System.Collections.Generic;
public class LoopExample
{
public void RunLoopExample()
{
var outerList = new string[]{"the", "quick", "brown", "fox"};
var innerList = new string[]{"jumps", "over", "the", "lazy", "dog"};
// define the resultList variable outside the outer loop
var resultList = new List<string>();
for(int outerIndex = 0; outerIndex < outerList.Length; outerIndex ++)
{
var outerValue = outerList[outerIndex];
for(int innerIndex = 0; innerIndex < innerList.Length; innerIndex++)
{
var innerValue = innerList[innerIndex];
resultList.Add(string.Format("{0}->{1}; ", outerValue, innerValue));
}
}
// use the resultList variable outside the outer loop
foreach(var result in resultList )
{
Console.WriteLine(result);
}
}
}
In your example, you would set the dataSource to the resultList
Repeater2.DataSource = resultList;
Repeater2.DataBind();

Related

Splitting an element of an array

In my C# program (I'm new to C# so I hope that I'm doing things correctly), I'm trying to read in all of the lines from a text file, which will look something along the lines of this, but with more entries (these are fictional people so don't worry about privacy):
Logan Babbleton ID #: 0000011 108 Crest Circle Mr. Logan M. Babbleton
Pittsburgh PA 15668 SSN: XXX-XX-XXXX
Current Program(s): Bachelor of Science in Cybersecurity
Mr. Carter J. Bairn ID #: 0000012 21340 North Drive Mr. Carter Joseph Bairn
Pittsburgh PA 15668 SSN: XXX-XX-XXXX
Current Program(s): Bachelor of Science in Computer Science
I have these lines read into an array, concentrationArray and want to find the lines that contain the word "Current", split them at the "(s): " in "Program(s): " and print the words that follow. I've done this earlier in my program, but splitting at an ID instead, like this:
nameLine = nameIDLine.Split(new string[] { "ID" }, StringSplitOptions.None)[1];
However, whenever I attempt to do this, I get an error that my index is out of the bounds of my split array (not my concentrationArray). Here's what I currently have:
for (int i = 0; i < concentrationArray.Length; i++)
{
if (concentrationArray[i].Contains("Current"))
{
lstTest.Items.Add(concentrationArray[i].Split(new string[] { "(s): " }, StringSplitOptions.None)[1]);
}
}
Where I'm confused is that if I change the index to 0 instead of 1, it will print everything out perfectly, but it will print out the first half, instead of the second half, which is what I want. What am I doing wrong? Any feedback is greatly appreciated since I'm fairly new at C# and would love to learn what I can. Thanks!
Edit - The only thing that I could think of was that maybe sometimes there wasn't anything after the string that I used to separate each element, but when I checked my text file, I found that was not the case and there is always something following the string used to separate.
You should check the result of split before trying to read at index 1.
If your line doesn't contain a "(s): " your code will crash with the exception given
for (int i = 0; i < concentrationArray.Length; i++)
{
if (concentrationArray[i].Contains("Current"))
{
string[] result = concentrationArray[i].Split(new string[] { "(s): " }, StringSplitOptions.None);
if(result.Length > 1)
lstTest.Items.Add(result[1]);
else
Console.WriteLine($"Line {i} has no (s): followeed by a space");
}
}
To complete the answer, if you always use index 0 then there is no error because when no separator is present in the input string then the output is an array with a single element containing the whole unsplitted string
If the line will always starts with
Current Program(s):
then why don't you just replace it with empty string like this:
concentrationArray[i].Replace("Current Program(s): ", "")
It is perhaps a little easier to understand and more reusable if you separate the concerns. It will also be easier to test. An example might be...
var allLines = File.ReadLines(#"C:\your\file\path\data.txt");
var currentPrograms = ExtractCurrentPrograms(allLines);
if (currentPrograms.Any())
{
lstTest.Items.AddRange(currentPrograms);
}
...
private static IEnumerable<string> ExtractCurrentPrograms(IEnumerable<string> lines)
{
const string targetPhrase = "Current Program(s):";
foreach (var line in lines.Where(l => !string.IsNullOrWhiteSpace(l)))
{
var index = line.IndexOf(targetPhrase);
if (index >= 0)
{
var programIndex = index + targetPhrase.Length;
var text = line.Substring(programIndex).Trim();
if (!string.IsNullOrWhiteSpace(text))
{
yield return text;
}
}
}
}
Here is a bit different approach
List<string> test = new List<string>();
string pattern = "Current Program(s):";
string[] allLines = File.ReadAllLines(#"C:\Users\xyz\Source\demo.txt");
foreach (var line in allLines)
{
if (line.Contains(pattern))
{
test.Add(line.Substring(line.IndexOf(pattern) + pattern.Length));
}
}
or
string pattern = "Current Program(s):";
lstTest.Items.AddRange(File.ReadLines(#"C:\Users\ODuritsyn\Source\demo.xml")
.Where(line => line.Contains(pattern))
.Select(line => line.Substring(line.IndexOf(pattern) + pattern.Length)));

Reading data form a .txt file and adding it to my Database

I've been working on a school assignment for a while and I have noticed I need a little help finishing it up. Specifically, I need help converting/importing a FlatFile.txt into my normalized DataBase in .
My flatfile has many rows, and in each row there are many attributes separated by a ' | '.
How can I add each line and take every element in the line to its unique corresponding attributes in my DataBase (assuming I already have my connection with my Database established)?
I know I might need to use something like:
hint*: comm.Parameters.AddWithValue("#FirstName", firstname);
How can make the first element of .txt file equal to firstname?
I hope this made sense.
Here is what I have so far:
string [] lines = File.ReadAllLines(pathString);
string[][] myRecords = new string[lines.Count() + 1][];
int k = 1;
foreach (var line in lines)
{
var values = line.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 1; i < values.Length; i++)
{
if (myRecords[k] == null)
{
myRecords[k] = new string[values.Length + 1];
}
myRecords[k][i] = values[i];
Console.WriteLine(myRecords[k][i]);
}
k++;
You should be able to add each item from a line to a corresponding name in the database, by using it's position in the line; something like:
comm.Parameters.AddWithValue("#FirstName", values[i]);
(Note: The exact syntax needed here will depend on what you use for this, but I'm assuming you'll be able to figure that part out).
...However, for something like that to work, you'll want to change the code parsing the line and remove StringSplitOptions.RemoveEmptyEntrie, since that will affect the resulting number of data-parts from each line.
An example:
var line = "one|two|||five|six";
// Will produce: {one, two, five, six}
var nonEmptyValues = line.Split(new char[] { '|' },
StringSplitOptions.RemoveEmptyEntries);
// Will produce {one, two, null, null, five, six}
var allValues = line.Split(new char[] { '|' });
The latter will allow your resulting array (values in your code) to always contain the correct number of "columns", which should make mapping from positions to DB column names easier.

remove first line from string builder / string c#

Okay so I'm trying to make a 'console' like text box within a form, however once you reach the bottom, instaid of being able to scroll up, it will just delete the top line, Im having some difficulties.
So far, when it gets to bottom it deletes the top line, however only once, it just carries on as normal. Here is my function:
StringBuilder sr = new StringBuilder();
public void writeLine(string input)
{
string firstline = "";
int numLines = Convert.ToString(sr).Split('\n').Length;
if (numLines > 15) //Max Lines
{
sr.Remove(0, Convert.ToString(sr).Split('\n').FirstOrDefault().Length);
}
sr.Append(input + "\r\n");
consoleTxtBox.Text = Convert.ToString(sr) + numLines;
}
Would be great if someone could fix this, thanks
Lucas
First, what's wrong with your solution: the reason it does not work is that it removes the content of the line, but it ignores the \n at the end. Adding 1 should fix that:
sr.Remove(0, Convert.ToString(sr).Split('\n').FirstOrDefault().Length+1);
// ^
// |
// This will take care of the trailing '\n' after the first line ---+
Now to doing it a simpler way: all you need to do is finding the first \n, and taking substring after it, like this:
string RemoveFirstLine(string s) {
return s.Substring(s.IndexOf(Environment.NewLine)+1);
}
Note that this code does not crash even when there are no newline characters in the string, i.e. when IndexOf returns -1 (in which case nothing is removed).
You can use the Lines property from the TextBox. This will get all the lines in the TextBox, as an array, then create a new array that doesn't include the first element (Skip(1)). It assigns this new array back to the textbox.
string[] lines = textBox.Lines;
textBox.Lines = lines.Skip(1).ToArray();
A simple alternative: you could split the string by Environment.NewLine and return all but the first:
public static string RemoveFirstLine(string input)
{
var lines = input.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
return string.Join(Environment.NewLine, lines.Skip(1));
}
Demo
you can remove this line
var lines = lines.Remove(0, lines.ToString().IndexOf(Environment.NewLine));
Most solutions does not seem to take into account the fact that Enviroment.NewLine can consist of multiple characters (len > 1).
public void RemoveFirstStringFromStringBuilder()
{
var lines = new StringBuilder();
lines.AppendLine("abc");
var firstLine = lines.ToString().IndexOf(Environment.NewLine, StringComparison.Ordinal);
if (firstLine >= 0)
lines.Remove(0, firstLine + Environment.NewLine.Length);
Console.WriteLine(lines.Length);
Console.WriteLine(lines.ToString());
}
Prints out: 0 and ""
What worked for me is:
var strBuilder = new StringBuilder();
strBuilder.AppendLine("ABC");
strBuilder.AppendLine("54");
strBuilder.AppendLine("04");
strBuilder.Remove(0, strBuilder.ToString().IndexOf(Environment.NewLine) + 2);
Console.WriteLine(strBuilder);
Solution with +1 didn't work for me, probably because of EOF in this context being interpreted as 2 chars (\r\n)

Parse Text File Into Dictionary

I have a text file that has several hundred configuration values. The general format of the configuration data is "Label:Value". Using C# .net, I would like to read these configurations, and use the Values in other portions of the code. My first thought is that I would use a string search to look for the Labels then parse out the values following the labels and add them to a dictionary, but this seems rather tedious considering the number of labels/values that I would have to search for. I am interested to hear some thoughts on a possible architecture to perform this task. I have included a small section of a sample text file that contains some of the labels and values (below). A couple of notes: The Values are not always numeric (as seen in the AUX Serial Number); For whatever reason, the text files were formatted using spaces (\s) rather than tabs (\t). Thanks in advance for any time you spend thinking about this.
Sample Text:
AUX Serial Number: 445P000023 AUX Hardware Rev: 1
Barometric Pressure Slope: -1.452153E-02
Barometric Pressure Intercept: 9.524336E+02
This is a nice little brain tickler. I think this code might be able to point you in the right direction. Keep in mind, this fills a Dictionary<string, string>, so there are no conversions of values into ints or the like. Also, please excuse the mess (and the poor naming conventions). It was a quick write-up based on my train of thought.
Dictionary<string, string> allTheThings = new Dictionary<string, string>();
public void ReadIt()
{
// Open the file into a streamreader
using (System.IO.StreamReader sr = new System.IO.StreamReader("text_path_here.txt"))
{
while (!sr.EndOfStream) // Keep reading until we get to the end
{
string splitMe = sr.ReadLine();
string[] bananaSplits = splitMe.Split(new char[] { ':' }); //Split at the colons
if (bananaSplits.Length < 2) // If we get less than 2 results, discard them
continue;
else if (bananaSplits.Length == 2) // Easy part. If there are 2 results, add them to the dictionary
allTheThings.Add(bananaSplits[0].Trim(), bananaSplits[1].Trim());
else if (bananaSplits.Length > 2)
SplitItGood(splitMe, allTheThings); // Hard part. If there are more than 2 results, use the method below.
}
}
}
public void SplitItGood(string stringInput, Dictionary<string, string> dictInput)
{
StringBuilder sb = new StringBuilder();
List<string> fish = new List<string>(); // This list will hold the keys and values as we find them
bool hasFirstValue = false;
foreach (char c in stringInput) // Iterate through each character in the input
{
if (c != ':') // Keep building the string until we reach a colon
sb.Append(c);
else if (c == ':' && !hasFirstValue)
{
fish.Add(sb.ToString().Trim());
sb.Clear();
hasFirstValue = true;
}
else if (c == ':' && hasFirstValue)
{
// Below, the StringBuilder currently has something like this:
// " 235235 Some Text Here"
// We trim the leading whitespace, then split at the first sign of a double space
string[] bananaSplit = sb.ToString()
.Trim()
.Split(new string[] { " " },
StringSplitOptions.RemoveEmptyEntries);
// Add both results to the list
fish.Add(bananaSplit[0].Trim());
fish.Add(bananaSplit[1].Trim());
sb.Clear();
}
}
fish.Add(sb.ToString().Trim()); // Add the last result to the list
for (int i = 0; i < fish.Count; i += 2)
{
// This for loop assumes that the amount of keys and values added together
// is an even number. If it comes out odd, then one of the lines on the input
// text file wasn't parsed correctly or wasn't generated correctly.
dictInput.Add(fish[i], fish[i + 1]);
}
}
So the only general approach that I can think of, given the format that you're limited to, is to first find the first colon on the line and take everything before it as the label. Skip all whilespace characters until you get to the first non-whitespace character. Take all non-whitespace characters as the value of the label. If there is a colon after the end of that value take everything after the end of the previous value to the colon as the next value and repeat. You'll also probably need to trim whitespace around the labels.
You might be able to capture that meaning with a regex, but it wouldn't likely be a pretty one if you could; I'd avoid it for something this complex unless you're entire development team is very proficient with them.
I would try something like this:
While string contains triple space, replace it with double space.
Replace all ": " and ": " (: with double space) with ":".
Replace all " " (double space) with '\n' (new line).
If line don't contain ':' than skip the line. Else, use string.Split(':'). This way you receive arrays of 2 strings (key and value). Some of them may contain empty characters at the beginning or at the end.
Use string.Trim() to get rid of those empty characters.
Add received key and value to Dictionary.
I am not sure if it solves all your cases but it's a general clue how I would try to do it.
If it works you could think about performance (use StringBuilder instead of string wherever it is possible etc.).
This is probably the dirtiest function I´ve ever written, but it works.
StreamReader reader = new StreamReader("c:/yourFile.txt");
Dictionary<string, string> yourDic = new Dictionary<string, string>();
StreamReader reader = new StreamReader("c:/yourFile.txt");
Dictionary<string, string> yourDic = new Dictionary<string, string>();
while (reader.Peek() >= 0)
{
string line = reader.ReadLine();
string[] data = line.Split(':');
if (line != String.Empty)
{
for (int i = 0; i < data.Length - 1; i++)
{
if (i != 0)
{
bool isPair;
if (i % 2 == 0)
{
isPair = true;
}
else
{
isPair = false;
}
if (isPair)
{
string keyOdd = data[i].Trim();
try { keyOdd = keyOdd.Substring(keyOdd.IndexOf(' ')).TrimStart(); }
catch { }
string valueOdd = data[i + 1].TrimStart();
try { valueOdd = valueOdd.Remove(valueOdd.IndexOf(' ')); } catch{}
yourDic.Add(keyOdd, valueOdd);
}
else
{
string keyPair = data[i].TrimStart();
keyPair = keyPair.Substring(keyPair.IndexOf(' ')).Trim();
string valuePair = data[i + 1].TrimStart();
try { valuePair = valuePair.Remove(valuePair.IndexOf(' ')); } catch { }
yourDic.Add(keyPair, valuePair);
}
}
else
{
string key = data[i].Trim();
string value = data[i + 1].TrimStart();
try { value = value.Remove(value.IndexOf(' ')); } catch{}
yourDic.Add(key, value);
}
}
}
}
How does it works?, well splitting the line you can know what you can get in every position of the array, so I just play with the even and odd values.
You will understand me when you debug this function :D. It fills the Dictionary that you need.
I have another idea. Does values contain spaces? If not you could do like this:
Ignore white spaces until you read some other char (first char of key).
Read string until ':' occures.
Trim key that you get.
Ignore white spaces until you read some other char (first char of value).
Read until you get empty char.
Trim value that you get.
If it is the end than stop. Else, go back to step 1.
Good luck.
Maybe something like this would work, be careful with the ':' character
StreamReader reader = new StreamReader("c:/yourFile.txt");
Dictionary<string, string> yourDic = new Dictionary<string, string>();
while (reader.Peek() >= 0)
{
string line = reader.ReadLine();
yourDic.Add(line.Split(':')[0], line.Split(':')[1]);
}
Anyway, I recommend to organize that file in some way that you´ll always know in what format it comes.

How to remove a duplicate set of characters in a string

For example a string contains the following (the string is variable):
http://www.google.comhttp://www.google.com
What would be the most efficient way of removing the duplicate url here - e.g. output would be:
http://www.google.com
I assume that input contains only urls.
string input = "http://www.google.comhttp://www.google.com";
// this will get you distinct URLs but without "http://" at the beginning
IEnumerable<string> distinctAddresses = input
.Split(new[] {"http://"}, StringSplitOptions.RemoveEmptyEntries)
.Distinct();
StringBuilder output = new StringBuilder();
foreach (string distinctAddress in distinctAddresses)
{
// when building the output, insert "http://" before each address so
// that it resembles the original
output.Append("http://");
output.Append(distinctAddress);
}
Console.WriteLine(output);
Efficiency has various definitions: code size, total execution time, CPU usage, space usage, time to write the code, etc. If you want to be "efficient", you should know which one of these you're trying for.
I'd do something like this:
string url = "http://www.google.comhttp://www.google.com";
if (url.Length % 2 == 0)
{
string secondHalf = url.Substring(url.Length / 2);
if (url.StartsWith(secondHalf))
{
url = secondHalf;
}
}
Depending on the kinds of duplicates you need to remove, this may or may not work for you.
collect strings into list and use distinct, if your string has http address you can apply regex http:.+?(?=((http:)|($)) with RegexOptions.SingleLine
var distinctList = list.Distinct(StringComparer.CurrentCultureIgnoreCase).ToList();
Given you don't know the length of the string, you don't know if something is double and you don't know what is double:
string yourprimarystring = "http://www.google.comhttp://www.google.com";
int firstCharacter;
string temp;
for(int i = 0; i <= yourprimarystring.length; i++)
{
for(int j = 0; j <= yourprimarystring.length; j++)
{
string search = yourprimarystring.substring(i,j);
firstCharacter = yourprimaryString.IndexOf(search);
if(firstCharacter != -1)
{
temp = yourprimarystring.substring(0,firstCharacter) + yourprimarystring.substring(firstCharacter + j - i,yourprimarystring.length)
yourprimarystring = temp;
}
}
This itterates through all your elements, takes all out from first to last letter and searches for them like this:
ABCDA - searches for A finds A exludes A, thats the problem, you need to specify how long the duplication needs to be if you want to make it variable, but maybe my code helps you.

Categories