I'm having issues with this code.
Everytime when it runs, it returns me the 'System.NullReferenceException'.
// Clear out the Array of code words
wordBuffer = null;
Int32 syntaxCount = 0;
// Create the regular expression object to match against the string
Regex defaultRegex = new Regex(#"\w+|[^A-Za-z0-9_ \f\t\v]",
RegexOptions.IgnoreCase | RegexOptions.Singleline);
Match wordMatch;
// Loop through the string and continue to record
// words and symbols and their corresponding positions and lengths
for (wordMatch = defaultRegex.Match(s); wordMatch.Success; wordMatch = wordMatch.NextMatch())
{
var word = new Object[3] { wordMatch.Value, wordMatch.Index, wordMatch.Length };
wordBuffer[syntaxCount] = word;
Debug.WriteLine("Found = " + word[0]);
syntaxCount++;
}
// return the number of symbols and words
return syntaxCount;
The exception occurs on those lines:
Debug.WriteLine("Found = " + word[0]);
syntaxCount++;
Specifically when trying to get the word[0] value, and on the second line with the syntaxCount, but none of those values are null, as you can see in the image below:
The variable "s" is just a line of a RichEditBox, word[0] has a value, so why is it returning the NullReferenceException? syntaxCount has a value too :/
You are getting the exception on the line wordBuffer[syntaxCount] = word;
You are using the wrong approach for storing the results. Arrays are not created automatically and they do not grow automatically. I.e., you need to define their size in advance with string[] arr = new string[size]. Use a list instead, as you do not know the size in advance here. Lists grow automatically:
// Initialize with
var wordBuffer = new List<string>();
// ...
// And then add a word to the list with
wordBuffer.Add(word);
You query the number of entries with wordBuffer.Count and you can access the items as in an array, once they have been added: wordBuffer[i], where the index goes from 0 to wordBuffer.Count - 1. This makes the variable syntaxCount superfluous.
And of course, you can loop through a list with foreach.
Related
My problem is that I want to extract the first number in a string.
The format of the string is as such
string text = "Board the DT line, go 1 stops toward Test";
What I want is the value 1. This is how I tried to do it
int digit1 = int.Parse(text.Substring(text.IndexOf("go")+1, text.IndexOf("stops")-1));
The error that I got was An unhandled exception of type 'System.FormatException' occurred in mscorlib.dll
Additional information: Input string was not in a correct format.
If you are new to programming you may want to break this down into smaller tasks.
For instance you can start by hardcoding the substring values to ensure you get the correct result
var str = "Board the DT line, go 1 stops toward Test";
var number = str.Substring(22, 1);
when you know you have the correct number you can look at how to get those values programmatically.
var index = str.IndexOf("go "); //gives you 19
var index = str.IndexOf("go ") + 3 //add 3 to get the start index
then you substitute the hard coded value for the code
var number = str.Substring(str.IndexOf("go ") + 3, 1);
You could also use regex: [0-9]+. This pattern extracts all of the numbers in the string.
var matches = Regex.Matches("Board the DT line, go 1 stops toward Test", "[0-9]+");
foreach(Match match in matches)
{
int number = int.Parse(match.Value);
Console.WriteLine(number);
}
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();
I'm working in c# (.Net4 using Visual Studio) and I'm trying to figure out an algorithm to append incremental numbers to strings entered, based on existing strings in the program. Not doing too well searching around for an answer.
I have a List<string>. An example would be
{"MyItem (2)", "MyItem", "Other thing", "string here", "MyItem (1)"}
So say the user wants to add another string to this list, and they've selected "MyItem" as the string to add. So given the input and the existing list, the algorithm would return "MyItem (3)" as the new string to add.
It's the same function as in Windows Explorer where you keep adding New Folders ("New Folder (1)", "New Folder (2)" and on and on)
I'm trying just looping through the list and figuring out what the next logical number should be but I'm getting stuck (and the code's getting large). Anyone know an elegent way of doing this? (I'm not too good with Regex so maybe that's what I'm missing)
Get the input and search for it, if it's present in the list then get the count and concatenate input string and count + 1 otherwise just add the input to the list:
var input = Console.ReadLine(); // just for example
if(list.Any(x => x == input))
{
var count = list.Count(x => x == input);
list.Add(string.Format("{0} ({1})", input, count+1);
}
else list.Add(input);
This should work:
var list = new List<string>{"MyItem (2)", "MyItem", "Other thing", "string here", "MyItem (1)"} ;
string str = "MyItem";
string newStr = str;
int i = 0;
while(list.Contains(newStr))
{
i++;
newStr = string.Format("{0} ({1})",str,i);
}
// newStr = "MyItem (3)"
The following is a useful extension method that I came up with to simulate the behaviour of Windows Explorer.
The previous answers I feel were too simple and only partially satisfied the requirements, they were also not presented in a way that you could easily reuse them.
This solution is based on you first identifying the list of strings that you want to compare against, they might come from a file system, or database, its up to you to resolve the list of values from your business domain, then the process of identifying the duplicates and generating a unique values is very repeatable.
Extension Method:
/// <summary>
/// Generate a uniquely numbered string to insert into this list
/// Uses convention of appending the value with the duplication index number in brackets "~ (#)"
/// </summary>
/// <remarks>This will not actually add this list</remarks>
/// <param name="input">The string to evaluate against this collection</param>
/// <param name="comparer">[Optional] One of the enumeration values that specifies how the strings will be compared, will default to OrdinalIgnoreCase </param>
/// <returns>A numbered variant of the input string that would be unique in the list of current values</returns>
public static string GetUniqueString(this IList<string> currentValues, string input, StringComparison comparison = StringComparison.OrdinalIgnoreCase)
{
// This matches the pattern we are using, i.e. "A String Value (#)"
var regex = new System.Text.RegularExpressions.Regex(#"\(([0-9]+)\)$");
// this is the comparison value that we want to increment
string prefix = input.Trim();
string result = input.Trim();
// let it through if there is no current match
if (currentValues.Any(x => x.Equals(input, comparison)))
{
// Identify if the input value has already been incremented (makes this more reusable)
var inputMatch = regex.Match(input);
if (inputMatch.Success)
{
// this is the matched value
var number = inputMatch.Groups[1].Captures[0].Value;
// remove the numbering from the alias to create the prefix
prefix = input.Replace(String.Format("({0})", number), "").Trim();
}
// Now evaluate all the existing items that have the same prefix
// NOTE: you can do this as one line in Linq, this is a bit easier to read
// I'm trimming the list for consistency
var potentialDuplicates = currentValues.Select(x => x.Trim()).Where(x => x.StartsWith(prefix, comparison));
int count = 0;
int maxIndex = 0;
foreach (string item in potentialDuplicates)
{
// Get the index from the current item
var indexMatch = regex.Match(item);
if (indexMatch.Success)
{
var index = int.Parse(indexMatch.Groups[1].Captures[0].Value);
var test = item.Replace(String.Format("({0})", index), "").Trim();
if (test.Equals(prefix, comparison))
{
count++;
maxIndex = Math.Max(maxIndex, index);
}
}
}
int nextIndex = Math.Max(maxIndex, count) + 1;
result = string.Format("{0} ({1})", prefix, nextIndex);
}
return result;
}
Implementation:
var list = new string [] { "MyItem (2)", "MyItem", "Other thing", "string here", "MyItem (1)" };
string input = Console.ReadLine(); // simplify testing, thanks #selman-genç
var result = list.GetUniqueString(input, StringComparison.OrdinalIgnoreCase);
// Display the result, you can add it to the list or whatever you need to do
Console.WriteLine(result);
Input | Result
---------------------------------
MyItem | MyItem (3)
myitem (1) | myitem (3)
MyItem (3) | MyItem (3)
MyItem (4) | MyItem (4)
MyItem 4 | MyItem 4
String Here | String Here (1)
a new value | a new value
Pseudo-code:
If the list has no such string, add it to the list.
Otherwise, set variable N = 1.
Scan the list and look for strings like the given string + " (*)" (here Regex would help).
If any string is found, take the number from the braces and compare it against N. Set N = MAX( that number + 1, N ).
After the list has been scanned, N contains the number to add.
So, add the string + " (N)" to the list.
I am trying to process a report from a system which gives me the following code
000=[GEN] OK {Q=1 M=1 B=002 I=3e5e65656-e5dd-45678-b785-a05656569e}
I need to extract the values between the curly brackets {} and save them in to variables. I assume I will need to do this using regex or similar? I've really no idea where to start!! I'm using c# asp.net 4.
I need the following variables
param1 = 000
param2 = GEN
param3 = OK
param4 = 1 //Q
param5 = 1 //M
param6 = 002 //B
param7 = 3e5e65656-e5dd-45678-b785-a05656569e //I
I will name the params based on what they actually mean. Can anyone please help me here? I have tried to split based on spaces, but I get the other garbage with it!
Thanks for any pointers/help!
If the format is pretty constant, you can use .NET string processing methods to pull out the values, something along the lines of
string line =
"000=[GEN] OK {Q=1 M=1 B=002 I=3e5e65656-e5dd-45678-b785-a05656569e}";
int start = line.IndexOf('{');
int end = line.IndexOf('}');
string variablePart = line.Substring(start + 1, end - start);
string[] variables = variablePart.Split(' ');
foreach (string variable in variables)
{
string[] parts = variable.Split('=');
// parts[0] holds the variable name, parts[1] holds the value
}
Wrote this off the top of my head, so there may be an off-by-one error somewhere. Also, it would be advisable to add error checking e.g. to make sure the input string has both a { and a }.
I would suggest a regular expression for this type of work.
var objRegex = new System.Text.RegularExpressions.Regex(#"^(\d+)=\[([A-Z]+)\] ([A-Z]+) \{Q=(\d+) M=(\d+) B=(\d+) I=([a-z0-9\-]+)\}$");
var objMatch = objRegex.Match("000=[GEN] OK {Q=1 M=1 B=002 I=3e5e65656-e5dd-45678-b785-a05656569e}");
if (objMatch.Success)
{
Console.WriteLine(objMatch.Groups[1].ToString());
Console.WriteLine(objMatch.Groups[2].ToString());
Console.WriteLine(objMatch.Groups[3].ToString());
Console.WriteLine(objMatch.Groups[4].ToString());
Console.WriteLine(objMatch.Groups[5].ToString());
Console.WriteLine(objMatch.Groups[6].ToString());
Console.WriteLine(objMatch.Groups[7].ToString());
}
I've just tested this out and it works well for me.
Use a regular expression.
Quick and dirty attempt:
(?<ID1>[0-9]*)=\[(?<GEN>[a-zA-Z]*)\] OK {Q=(?<Q>[0-9]*) M=(?<M>[0-9]*) B=(?<B>[0-9]*) I=(?<I>[a-zA-Z0-9\-]*)}
This will generate named groups called ID1, GEN, Q, M, B and I.
Check out the MSDN docs for details on using Regular Expressions in C#.
You can use Regex Hero for quick C# regex testing.
You can use String.Split
string[] parts = s.Split(new string[] {"=[", "] ", " {Q=", " M=", " B=", " I=", "}"},
StringSplitOptions.None);
This solution breaks up your report code into segments and stores the desired values into an array.
The regular expression matches one report code segment at a time and stores the appropriate values in the "Parsed Report Code Array".
As your example implied, the first two code segments are treated differently than the ones after that. I made the assumption that it is always the first two segments that are processed differently.
private static string[] ParseReportCode(string reportCode) {
const int FIRST_VALUE_ONLY_SEGMENT = 3;
const int GRP_SEGMENT_NAME = 1;
const int GRP_SEGMENT_VALUE = 2;
Regex reportCodeSegmentPattern = new Regex(#"\s*([^\}\{=\s]+)(?:=\[?([^\s\]\}]+)\]?)?");
Match matchReportCodeSegment = reportCodeSegmentPattern.Match(reportCode);
List<string> parsedCodeSegmentElements = new List<string>();
int segmentCount = 0;
while (matchReportCodeSegment.Success) {
if (++segmentCount < FIRST_VALUE_ONLY_SEGMENT) {
string segmentName = matchReportCodeSegment.Groups[GRP_SEGMENT_NAME].Value;
parsedCodeSegmentElements.Add(segmentName);
}
string segmentValue = matchReportCodeSegment.Groups[GRP_SEGMENT_VALUE].Value;
if (segmentValue.Length > 0) parsedCodeSegmentElements.Add(segmentValue);
matchReportCodeSegment = matchReportCodeSegment.NextMatch();
}
return parsedCodeSegmentElements.ToArray();
}
I have the following string which i would like to retrieve some values from:
============================
Control 127232:
map #;-
============================
Control 127235:
map $;NULL
============================
Control 127236:
I want to take only the Control . Hence is there a way to retrieve from that string above into an array containing like [127232, 127235, 127236]?
One way of achieving this is with regular expressions, which does introduce some complexity but will give the answer you want with a little LINQ for good measure.
Start with a regular expression to capture, within a group, the data you want:
var regex = new Regex(#"Control\s+(\d+):");
This will look for the literal string "Control" followed by one or more whitespace characters, followed by one or more numbers (within a capture group) followed by a literal string ":".
Then capture matches from your input using the regular expression defined above:
var matches = regex.Matches(inputString);
Then, using a bit of LINQ you can turn this to an array
var arr = matches.OfType<Match>()
.Select(m => long.Parse(m.Groups[1].Value))
.ToArray();
now arr is an array of long's containing just the numbers.
Live example here: http://rextester.com/rundotnet?code=ZCMH97137
try this (assuming your string is named s and each line is made with \n):
List<string> ret = new List<string>();
foreach (string t in s.Split('\n').Where(p => p.StartsWith("Control")))
ret.Add(t.Replace("Control ", "").Replace(":", ""));
ret.Add(...) part is not elegant, but works...
EDITED:
If you want an array use string[] arr = ret.ToArray();
SYNOPSYS:
I see you're really a newbie, so I try to explain:
s.Split('\n') creates a string[] (every line in your string)
.Where(...) part extracts from the array only strings starting with Control
foreach part navigates through returned array taking one string at a time
t.Replace(..) cuts unwanted string out
ret.Add(...) finally adds searched items into returning list
Off the top of my head try this (it's quick and dirty), assuming the text you want to search is in the variable 'text':
List<string> numbers = System.Text.RegularExpressions.Regex.Split(text, "[^\\d+]").ToList();
numbers.RemoveAll(item => item == "");
The first line splits out all the numbers into separate items in a list, it also splits out lots of empty strings, the second line removes the empty strings leaving you with a list of the three numbers. if you want to convert that back to an array just add the following line to the end:
var numberArray = numbers.ToArray();
Yes, the way exists. I can't recall a simple way for It, but string is to be parsed for extracting this values. Algorithm of it is next:
Find a word "Control" in string and its end
Find a group of digits after the word
Extract number by int.parse or TryParse
If not the end of the string - goto to step one
realizing of this algorithm is almost primitive..)
This is simplest implementation (your string is str):
int i, number, index = 0;
while ((index = str.IndexOf(':', index)) != -1)
{
i = index - 1;
while (i >= 0 && char.IsDigit(str[i])) i--;
if (++i < index)
{
number = int.Parse(str.Substring(i, index - i));
Console.WriteLine("Number: " + number);
}
index ++;
}
Using LINQ for such a little operation is doubtful.