I have a class that has a collection of strings that is used to validate values before storing them. The declaration for the collection looks like this:
public readonly System.Collections.Specialized.StringCollection RetentionRange =
new System.Collections.Specialized.StringCollection()
{ "NR", "AR", "PE", "EX", "LI", "TE", "FR" };
I'd like to maintain the list of valid codes outside of the compiled class. How do I go about that? BTW, there's no requirement for the strings to be limited to two characters, they just happen to be in the current scheme.
EDIT: By "external data" I mean something like a config file.
You can store a StringCollection in the AppSettings.
Each value is separated by a new line.
Here's a screenshot (german IDE but it might be helpful anyway)
You can read it in this way:
var myStringCollection = Properties.Settings.Default.MyCollection;
foreach (String value in myStringCollection)
{
// do something
}
Storing it in a text file is an option.
How to store:
var dir = #"somedirectory\textfile.txt";
var text = string.Join(",",RetentionRange.Cast<string>());
File.WriteAllText(dir,text);
How to retrieve:
var text= File.ReadAllText(#"somedirectory\textfile.txt");
foreach(var str in text.Split(","))
RetentionRange.Add(text);
The right answer to your question depends a great deal on why you want to store the strings outside the assembly.
Assuming the reason you want this is because the collection of strings is expected to change over time, I would suggest you create your own System.Configuration.ConfigurationSection implementation that defines one of the elements as a System.Configuration.ConfigurationElementCollection instance. If this is a tad too complicated for your requirements, then an appSettings key with a value consisting of a comma separated list of strings (from which you would build your StringCollection at runtime) might actually be a better solution.
The answers to this question have examples of both approaches.
Related
I have a file that is formatted this way --
{2000}000000012199{3100}123456789*{3320}110009558*{3400}9876
54321*{3600}CTR{4200}D2343984*JOHN DOE*1232 STREET*DALLAS TX
78302**{5000}D9210293*JANE DOE*1234 STREET*SUITE 201*DALLAS
TX 73920**
Basically, the number in curly brackets denotes field, followed by the value for that field. For example, {2000} is the field for "Amount", and the value for it is 121.99 (implied decimal). {3100} is the field for "AccountNumber" and the value for it is 123456789*.
I am trying to figure out a way to split the file into "records" and each record would contain the record type (the value in the curly brackets) and record value, but I don't see how.
How do I do this without a loop going through each character in the input?
A different way to look at it.... The { character is a record delimiter, and the } character is a field delimiter. You can just use Split().
var input = #"{2000}000000012199{3100}123456789*{3320}110009558*{3400}987654321*{3600}CTR{4200}D2343984*JOHN DOE*1232 STREET*DALLAS TX78302**{5000}D9210293*JANE DOE*1234 STREET*SUITE 201*DALLASTX 73920**";
var rows = input.Split( new [] {"{"} , StringSplitOptions.RemoveEmptyEntries);
foreach (var row in rows)
{
var fields = row.Split(new [] { "}"}, StringSplitOptions.RemoveEmptyEntries);
Console.WriteLine("{0} = {1}", fields[0], fields[1]);
}
Output:
2000 = 000000012199
3100 = 123456789*
3320 = 110009558*
3400 = 987654321*
3600 = CTR
4200 = D2343984*JOHN DOE*1232 STREET*DALLAS TX78302**
5000 = D9210293*JANE DOE*1234 STREET*SUITE 201*DALLASTX 73920**
Fiddle
This regular expression should get you going:
Match a literal {
Match 1 or more digts ("a number")
Match a literal }
Match all characters that are not an opening {
\{\d+\}[^{]+
It assumes that the values itself cannot contain an opening curly brace. If that's the case, you need to be more clever, e.g. #"\{\d+\}(?:\\{|[^{])+" (there are likely better ways)
Create a Regex instance and have it match against the text. Each "field" will be a separate match
var text = #"{123}abc{456}xyz";
var regex = new Regex(#"\{\d+\}[^{]+", RegexOptions.Compiled);
foreach (var match in regex.Matches(text)) {
Console.WriteLine(match.Groups[0].Value);
}
This doesn't fully answer the question, but it was getting too long to be a comment, so I'm leaving it here in Community Wiki mode. It does, at least, present a better strategy that may lead to a solution:
The main thing to understand here is it's rare — like, REALLY rare — to genuinely encounter a whole new kind of a file format for which an existing parser doesn't already exist. Even custom applications with custom file types will still typically build the basic structure of their file around a generic format like JSON or XML, or sometimes an industry-specific format like HL7 or MARC.
The strategy you should follow, then, is to first determine exactly what you're dealing with. Look at the software that generates the file; is there an existing SDK, reference, or package for the format? Or look at the industry surrounding this data; is there a special set of formats related to that industry?
Once you know this, you will almost always find an existing parser ready and waiting, and it's usually as easy as adding a NuGet package. These parsers are genuinely faster, need less code, and will be less susceptible to bugs (because most will have already been found by someone else). It's just an all-around better way to address the issue.
Now what I see in the question isn't something I recognize, so it's just possible you genuinely do have a custom format for which you'll need to write a parser from scratch... but even so, it doesn't seem like we're to that point yet.
Here is how to do it in linq without slow regex
string x = "{2000}000000012199{3100}123456789*{3320}110009558*{3400}987654321*{3600}CTR{4200}D2343984*JOHN DOE*1232 STREET*DALLAS TX78302**{5000}D9210293*JANE DOE*1234 STREET*SUITE 201*DALLASTX 73920**";
var result =
x.Split('{',StringSplitOptions.RemoveEmptyEntries)
.Aggregate(new List<Tuple<string, string>>(),
(l, z) => { var az = z.Split('}');
l.Add(new Tuple<string, string>(az[0], az[1]));
return l;})
LinqPad output:
What would be the fastest way to check if a string contains any matches in a string array in C#? I can do it using a loop, but I think that would be too slow.
Using LINQ:
return array.Any(s => s.Equals(myString))
Granted, you might want to take culture and case into account, but that's the general idea.
Also, if equality is not what you meant by "matches", you can always you the function you need to use for "match".
I really couldn't tell you if this is absolutely the fastest way, but one of the ways I have commonly done this is:
This will check if the string contains any of the strings from the array:
string[] myStrings = { "a", "b", "c" };
string checkThis = "abc";
if (myStrings.Any(checkThis.Contains))
{
MessageBox.Show("checkThis contains a string from string array myStrings.");
}
To check if the string contains all the strings (elements) of the array, simply change myStrings.Any in the if statement to myStrings.All.
I don't know what kind of application this is, but I often need to use:
if (myStrings.Any(checkThis.ToLowerInvariant().Contains))
So if you are checking to see user input, it won't matter, whether the user enters the string in CAPITAL letters, this could easily be reversed using ToLowerInvariant().
Hope this helped!
That works fine for me:
string[] characters = new string[] { ".", ",", "'" };
bool contains = characters.Any(c => word.Contains(c));
You could combine the strings with regex or statements, and then "do it in one pass," but technically the regex would still performing a loop internally. Ultimately, looping is necessary.
If the "array" will never change (or change only infrequently), and you'll have many input strings that you're testing against it, then you could build a HashSet<string> from the array. HashSet<T>.Contains is an O(1) operation, as opposed to a loop which is O(N).
But it would take some (small) amount of time to build the HashSet. If the array will change frequently, then a loop is the only realistic way to do it.
I'm getting stuck clicking a listbox item (the items in my listbox is .txt files in a folder) and displaying the values in the .txt file.
the values in the .txt files are all seperated with a "," and I want each Split item to display in labels on my form.
my file path is: System.AppDomain.CurrentDomain.BaseDirectory + "data"
my .txt file names are the names of the selected item in my listbox.
I have a basic idea of what should happen, but I have no clue how to express this in code.
My Code:
private void custList_MouseClick(object sender, MouseEventArgs e)
{
string foldr = System.AppDomain.CurrentDomain.BaseDirectory + "data";
string file = custList.SelectedIndex.ToString();
}
Thanx in advance
Before i go on answering this question, please read How to ask. This will help you better understand this community and ask better questions(to get better support).
Next on, do some research. From a first glance, it looks like you are asking someone to do the homework for you. Anyways, i am not here to be tough on you. I will point you out a few things. Try to understand them and utilize them.
Note that even though it may seem as such but i am not a fan of spoon-feeding so be sincere and do your research.
Let's start with your text file. As you mentioned, it contains values. C#, being a versatile & mature language has a lot of functions,methods,classes pre-built to help boost your programming experience. Such a method is ReadAllText, a part of the File class. In the simplest words, this method opens a text file, reads it, returns it's value. A sample use of this method could be :
string TextFromFile = File.ReadAllText(File_Path_Goes_Here);
Moving on... Your text file has multiple values separated by comma(,). In such cases, each value needs to read as a separate value upon retrieving or displaying. So, you want a List of the values, end of story. In C#, you have a wide range of generic lists to use from. As the values in the text file are simple strings, you can use a List<string> in this regard. A basic usage example of List<string> would be :
List<string> TestList1 = new List<string>();
TestList1.Add("First Value"); TestList1.Add("Second Value");
///or
List<string> TestList1 = new List<string>(){ "First Value", "Second Value" };
In your particular case, File.ReadAllLines is worth an example. The method opens a text file, reads it, closes it. Of course it returns the value read from the text file, as an array. So, when passing values to the generic list, you can simply make use of this method. Example :
...... new List<string>(File.ReadAllLines(Path_Of_File_Goes_Here));
The only twist here is that the values in your text file are in a line(maybe) and also are separated by comma. So, what do you think should work here ? ReadAllText or ReadAllLines ? I will leave it upto you.
Once values are read from the file, we can make use of the Split function to split the values upon each occurrence of a comma(,). A simple example :
List<string> NameList = "Josh,Riley".Split(',').ToList<string>();
And last but not the least, the headline of the question which doesn't seem to have anything to do with the post itself, here's what you can take a look at :
Control Click Event
ListBox.GetItemText
Tip: The SelectedItem property of the ListBox class returns or sets the selected item of a listbox.
I hope this has been helpful. Do pay attention to all that's mentioned above. It may be a bit hard to follow up with at first, but remember, Consistency is the hallmark of the unimaginative.
....Yeah, that's not my quote. Gotcha!
I don't know where you want to show the values of your text file, so I will just provide you what you need to retrieve those informations.
To get values from your file:
public string[] GetValues()
{
string[] values;
using(StreamReader sr = new StreamReader(Path.Combine(foldr, file))
{
string text = sr.ReadToEnd();
values = text.Split(',');
}
return values;
}
Then you can show them using an array:
public void Main()
{
string[] values = GetValues();
foreach(var value in values)
{
Console.WriteLine(value);
}
}
Hope this helps.
I recently started learning about programming with C# and I have encountered a little problem with my small task that I got.
But first let me just go through a little bit what I learned so far about strings.
So, string text = Console.ReadLine(); saves whatever the user writes into that variable.
Next, I worked with a Backpack code where the user can 1. Add items in the backpack and 2. Present the items in the backpack. Here I worked with the += operator so that whenever the user added an item it would be added to the string variable.
Now I am working with a diary/blog code. The user can:
Write a new text (with a title).
Search and present the texts written.
I am stuck because I can't just have one string variable for the text that the users writes because it will be overwritten every time the user adds a new text. And I can't use += operator since I don't want to add more text to my string variable. Every time the user adds a new text it has to be saved into a new string variable (I guess?).
I just don't know how to write this code.
A good way to fix your issue is to use Classes. Maybe you can create a Blog Class with two properties Title and Body and then all you have to do is to simply create a list of Blogs.
class Blog
{
string Title {get;set;}
string Body {get;set;}
}
Each object of Blog Class represent a new post and a list of blog will give you the list of all the blog posts.
List<Blog> blogs = new List<Blog>();
You can use a generic collection like List. They are build for gathering items of one certain type. In your case it would be: List<string> allTexts. You can add strings to it with the Add method:
List<string> allTexts = new List<string>();
string newText = Console.ReadLine();
allTexts.Add(newText);
and you can access them via the [ ] operator
string textNr4 = allTexts[3];
Note: indexing starts with 0!
If you like to search for certain parts of a text you could use LINQ
string searchWord = "and";
List<string> allMatchedTextes = allTexts.Where(text=>text.Contains(searchWord)).ToList();
this will return all strings that contain the searchWord
Let's say I have an array of strings from executing this Split method
string[] parsed = message.Split(' ');
And then I want to store a certain value of this array in a new string
string name = parsed[3];
Now I remove this string from the array using an extension method, this method removes the value at the specified index and shifts everything back to fill the gap
parsed = parsed.RemoveAt(3);
I am aware that because strings are reference types in C# my name variable is now null, after searching a little I've been told that making exact copies of strings in C# is useless. What is the best and correct way to set the name variable as a new instance so that it does not get deleted after the .RemoveAt() call?
EDIT:
This is the best way that I found so far
string name = new string(parsed[3].ToCharArray());
Another way proposed by Willy David Jr
parsed = parsed.Where((source, index) => index != 3).ToArray();
EDIT 2:
Please disregard this question and read the approved answer, I misunderstood how reference types work.
You're misunderstanding how reference types work. Removing an object from an array does not modify that object in any way - it just means that the array no longer contains a reference to the object.
You can test this yourself. Run the code you included in the debugger (or a console app) and then view (or print out) the value of name at the end.
The thing that can trick you up with reference types occurs when there are two variables (or arrays or whatever) that hold a reference to the same object. In this case, changes made to the object via one variable will be reflected when the object is accessed via another variable - it's the same object, but with two different variables referencing it. If you want both variables to refer to their own "copy" of the object, you have to create a copy yourself and assign it to one of the variables.
However, in C#, the string type is immutable, meaning that once a string object is created there is no way to change that object. So there is never a reason to create a copy of a string. If there is a variable that references a particular string, you can be sure that no other reference can change it out from under you.
Why do you think your name variable should be null? It will stay untouched after removal from array. Your original code is enough to accomplish what you desire.
Are you sure that there is RemoveAt at your string? There is RemoveAt on Collections but not on string or string array per se.
You can do this instead:
List<string> lstParse = new List<string>();
foreach (var i in parsed)
{
lstParse.Add(i);
}
string name = parsed[3];
lstParse.RemoveAt(3);
To join again the list and convert it to string:
string strResult = string.Join(" ", lstParse.ToArray());
If you really want to remove index without a new list of object, disregard the code above and you can do this one line instead:
parsed = parsed.Where((source, index) => index != 3).ToArray();