one of my first posts, so do not expect too much of me please.
I have an array
string phrase = Value.Text;
string[] words = phrase.Split('\t', '\r');
Which splits the output by tab or return.
I then re-arrange that array to create an output - this caused some confusion so updating...
The Input is from a Spreadsheet, as an example, the array will contain the number for each of the items, So:
TV is Four
Video is Five
Radio is Seven
string TV = words[3];
string Video = words[2];
string Radio = words[1];
Then create an output:
this.OutPut.Text = NumberValue.Text;
this.OutPut.Text += '\t';
this.OutPut.Text += TV;
this.OutPut.Text += '\t';
this.OutPut.Text += DatePicker.Text;
The NumberValue comes from a TextBox - imagine this is the price
The DatePicker comes from a Date picker - imagine this is the date that the information was created (not the day in which it is entered)
The purpose is to copy the data to a template spreadsheet. However, the data must match the destination template spreadsheet - hence the array and output re-arranging.
This has been fine, while dealing with a small array, and a defined length array works fine - for example, just TV, Video and Radio.
I am now seeking to have an array 'upto' 100, but could be less.
I realise that this code is not good as it is going to be 200 lines of code and it also throws "index out of range" exceptions whenever an array is created that does not reach the last words [100] created or output.
So I was wondering if anyone had a better way of doing this? I don't need you to write the code, but give me an idea, and I can go learn...but at the moment, I don't really know what I am looking for or how to search for it, as I doubt I have the language required to find it.
So any pointers gratefully received.
I hope the updates help explain the problem.
Without knowing more about your input/output, it's really hard to make useful suggestions.
Here's an idea that you might find useful, though. Use a List<string> to hold the order of the new items, then join them together when you need to combine then into one line.
Big picture idea:
string phrase = Value.Text;
string[] words = Value.Text.Split(new char[] { '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
List<string> values = new List<string>();
// add things to values, from words, in whatever order you need them to be
values.Add(words[3]);
values.Add(words[4]);
values.Add(words[1]);
string newLine = String.Join("\t", values);
OutPut.AppendText(newLine + Environment.NewLine);
If you already know the order of the indices, the "3", "4", "1" in my example, then you could use an ARRAY to hold those values and then iterate over them:
string phrase = Value.Text;
string[] words = Value.Text.Split(new char[] { '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
int[] newIndexOrder = { 3, 4, 1 };
List<string> values = new List<string>();
foreach(int i in newIndexOrder )
{
values.Add(words[i]);
}
string newLine = String.Join("\t", values);
OutPut.AppendText(newLine + Environment.NewLine);
string phrase = Value.Text;
string[] words = Value.Text.Split(new char[] { '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
From the comments:
if every 12 values/words I need a line break?
I've added in a StringBuilder to accumulate the output, adding in a break whenever we hit twelve items:
int[] newIndexOrder = { 3, 4, 1 };
List<string> values = new List<string>();
StringBuilder sb = new System.Text.StringBuilder();
foreach(int i in newIndexOrder)
{
values.Add(words[i]);
if (values.Count == 12)
{
sb.AppendLine(String.Join("\t", values));
values.Clear();
}
}
if (values.Count > 0)
{
sb.AppendLine(String.Join("\t", values));
}
OutPut.AppendText(sb.ToString());
You can use a foreach loop and avoid writing 200 lines of code.
Example :
string phrase = Value.Text;
string[] words = phrase.Split('\t', '\r');
foreach (string word in words)
{
this.OutPut.text += word + '\t';
}
Related
This is more a question of whether this is possible.
I have an input box, 6 items go into the input box, this is an example string that forms the array:
Monday, Tuesday, April, February, Tomorrow, 42
These words can change, but their order is important. They are separated by a tab.
I want the 1st, 3rd, and the 6th word from this array. I would like to place them into an object - and if at all possible, but other items from other sources into that object in a particular order - so that I can then refer back to that object so that I do not have to write out long sections of code each time I need to output these 3 items.
My current code is unwieldy and I am looking for a better solution.
For reference my current code:
string phrase = value.Text;
string[] words = phrase.Split('\t');
string Word1 = words[1];
string Word2 = words[3];
string Word3 = words[6];
this.Output.Text = Word1 + '\t';
this.Output.Text += TextBox1.Text + '\t';
this.Output.Text += Word2 + '\t';
this.Output.Text += TextBox2.Text + '\t';
this.Output.Text += Word3;
This code works, but I am starting to work with larger arrays, requiring larger outputs and I am finding that I need to refer back to the same output multiple times.
Imagine the above code running to Word12, from an array of 30 adding the information from 6 text boxes, and having to have that output created 15 times in different places in the program. Also, you can see that the length of the code stops making sense.
If I could create an object containing all of that information, I could create it once, and then refer back to it as often as I needed.
Any insight or direction on how to proceed gratefully received.
Based on my understanding you are looking for below solution. If I missed something then please let me know.
Firstly you can store value.Text into a list of string by splitting by '\t'.
Create an array to store indexes for which you want to pick words.
Based on stored indexes you can pick words and store in a final wordslist.
Create an array to store dynamic textboxes text.
Loop on these stored textboxes text array and insert at alternate position in final wordlist.
At last join wordlist separated by '\t' and show as output.
Below is the code:
string finalOutput = string.Empty;
List<string> wordsList = new List<string>();
string phrase = value.Text;// "Monday\tTuesday\tApril\tFebruary\tTomorrow\t42";
string[] words = phrase.Split('\t');
List<int> wordsIndexes = new List<int> { 1, 3, 6 }; //this is based on ur requirment
List<string> textBoxesText = new List<string>() { TextBox1.Text, TextBox2.Text };
wordsIndexes.ForEach(i => wordsList.Add(words[i-1]));
int insertAtIndex = 1;
for (int i = 0; i < textBoxesText.Count; i++)
{
if (wordsList.Count >= insertAtIndex)
{
wordsList.Insert(insertAtIndex, textBoxesText[i]);
insertAtIndex += 2;
}
}
finalOutput = string.Join('\t', wordsList);
Not sure if I understand correctly, but I think that you could use a list and add the words there, using a list of indexes like so:
string phrase = value.Text;
string[] words = phrase.Split('\t');
List<int> indexes = new List<int> { 1, 3, 6 }; //you can add more indexes here...
List<string> wordsList = new List<string>();
indexes.Foreach(i => wordsList.add(words[i]));
With this implementation, you have all the words you need in the list and you can easily add more just adding or removing any index you want. And you can refer the list whenever you need to.
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)));
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.
I would need some help with matching data in this example string:
req:{REQUESTER_NAME},key:{abc},act:{UPDATE},sku:{ABC123,DEF-123},qty:{10,5}
Essentially, every parameter is separated by "," but it is also included within {} and I need some help with regex as I am not that good with it.
Desired Output:
req = "REQUESTER_NAME"
key = "abc"
act = "UPDATE"
sku[0] = "ABC123"
sku[1] = "DEF-123"
qty[0] = 10
qty[1] = 5
I would suggest you do the following
Use String Split with ',' character as the separator (eg output req:{REQUESTER_NAME})
With each pair of data, do String Split with ';' character as the separator (eg output "req", "{REQUESTER_NAME}")
Do a String Replace for characters '{' and '}' with "" (eg output REQUESTER_NAME)
Do a String Split again with ',' character as separator (eg output "ABC123", "DEF-123")
That should parse it for you perfectly. You can store the results into your data structure as the results come in. (Eg. You can store the name at step 2 whereas the value for some might be available at Step 3 and for others at Step 4)
Hope That Helped
Note:
- If you don't know string split - http://www.dotnetperls.com/split-vbnet
- If you don't know string replace - http://www.dotnetperls.com/replace-vbnet
The below sample may helps to solve your problem. But here lot of string manipulations are there.
string input = "req:{REQUESTER_NAME},key:{abc},act:{UPDATE},sku:{ABC123,DEF-123},qty:{10,5}";
Console.WriteLine(input);
string[] words = input.Split(new string[] { "}," }, StringSplitOptions.RemoveEmptyEntries);
foreach (string item in words)
{
if (item.Contains(':'))
{
string modifiedString = item.Replace(",", "," + item.Substring(0, item.IndexOf(':')) + ":");
string[] wordsColl = modifiedString.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string item1 in wordsColl)
{
string finalString = item1.Replace("{", "");
finalString = finalString.Replace("}", "");
Console.WriteLine(finalString);
}
}
}
First, use Regex.Matches to get the parameters inside { and }.
string str = "req:{REQUESTER_NAME},key:{abc},act:{UPDATE},sku:{ABC123,DEF-123},qty:{10,5}";
MatchCollection matches = Regex.Matches(str,#"\{.+?\}");
string[] arr = matches.Cast<Match>()
.Select(m => m.Groups[0].Value.Trim(new char[]{'{','}',' '}))
.ToArray();
foreach (string s in arr)
Console.WriteLine(s);
output
REQUESTER_NAME
abc
UPDATE
ABC123,DEF-123
10,5
then use Regex.Split to get the parameter names
string[] arr1 = Regex.Split(str,#"\{.+?\}")
.Select(x => x.Trim(new char[]{',',':',' '}))
.Where(x => !string.IsNullOrEmpty(x)) //need this to get rid of empty strings
.ToArray();
foreach (string s in arr1)
Console.WriteLine(s);
output
req
key
act
sku
qty
Now you can easily traverse through the parameters. something like this
for(int i=0; i<arr.Length; i++)
{
if(arr1[i] == "req")
//arr[i] contains req parameters
else if(arr1[i] == "sku")
//arr[i] contains sku parameters
//use string.Split(',') to get all the sku paramters and process them
}
Kishore's answer is correct. This extension method may help implement that suggestion:
<Extension()>
Function WideSplit(InputString As String, SplitToken As String) As String()
Dim aryReturn As String()
Dim intIndex As Integer = InputString.IndexOf(SplitToken)
If intIndex = -1 Then
aryReturn = {InputString}
Else
ReDim aryReturn(1)
aryReturn(0) = InputString.Substring(0, intIndex)
aryReturn(1) = InputString.Substring(intIndex + SplitToken.Length)
End If
Return aryReturn
End Function
If you import System.Runtime.CompilerServices, you can use it like this:
Dim stringToParse As String = "req:{REQUESTER_NAME},key:{abc},act:{UPDATE},sku:{ABC123,DEF-123},qty:{10,5}"
Dim strTemp As String
Dim aryTemp As String()
strTemp = stringToParse.WideSplit("req:{")(1)
aryTemp = strTemp.WideSplit("},key:{")
req = aryTemp(0)
aryTemp = aryTemp(1).WideSplit("},act:{")
key = aryTemp(0)
'etc...
You may be able do this more memory efficiently, though, as this method creates a number of temporary string allocations.
Kishore's solution is perfect, but here is another solution that works with regex:
Dim input As String = "req:{REQUESTER_NAME},key:{abc},act:{UPDATE},sku:{ABC123,DEF-123},qty:{10,5}"
Dim Array = Regex.Split(input, ":{|}|,")
This does essentially the same, it uses regex to split on :{, } and ,. The solution might be a bit shorter though. The values will be put into the array like this:
"req", "REQUESTER_NAME","", ... , "qty", "10", "5", ""
Notice after the parameter and its value(s) there will be an empty string in the array. When looping over the array you can use this to let the program know when a new parameter starts. Then you can create a new array/data structure to store its values.
i have a textfile containing these kind of words
PEOPLE
John
0218753458
ENTERPRISE
stock
30%
HOME
Indiana
West Virginia
PEOPLE
Vahn
031245678
ENTERPRISE
Inc
50%
HOME
melbourne
Australia
i want to split these files into some strings that will divide the into each groups of PEOPLE, ENTERPRISE, and HOME. for example the output will be
part[0]
PEOPLE
John
0218753458
part[1]
ENTERPISE
stock
30%
part[2]
HOME
Indiana
West Virginia
and so on
i have a plan of using
EDIT #1 (thanks #Slade)
string[] part = s.Split(new string[] { "PEOPLE","ENTERPRISE","HOME" }, StringSplitOptions.None);
i can't change the structure.
is there any way to keep the HEADER? or better way to do this?
Don't use the || operator, that's for conditional/logical OR expressions. Instead, when filling elements of an array like you are doing, use a comma, like so:
string[] part = s.Split(new string[] { "PEOPLE", "ENTERPRISE", "HOME" }, StringSplitOptions.None);
However, unless you are always going to have these headings, it is not a good way of trying to split your text file. Instead, you need to define some structure to your file. For example, if you are always going to have headers in FULL CAPS, then you may want to start by splitting your text file into lines, then looping through each element and group the elements each time you hit a line containing only characters in FULL CAPS.
Personally, if possible, I would change the text file structure so you can flag headers with some symbol before or after: e.g. :THIS IS A HEADER. That way, you can split into lines then just look for the : symbol at the start of a line.
EDIT
For a sample approach on how to go about parsing this with the FULL CAPS headers, see my code example on PasteBin.
Note: The line ...
string[] lines = File.ReadAllLines(#"Sample.txt");
... could be replaced with ...
string textFromFile = File.ReadAllText(#"Sample.txt");
string[] lines = textFromFile.Split(new string[1] { System.Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
Using regex and because you want to keep the split strings in the results:
string[] tmp = Regex.Split(originalString, #"(PEOPLE|ENTERPRISE|HOME)");
List result = new List();
for(var i = 1; i < tmp.Count() - 1; i += 2) {
result.Add(tmp[i] + tmp[i+1]);
}
This gives you the result you want.
The reason why I'm concatenating the tmp array is because as of .NET 2.0, the Regex.Split will return the split strings as part of the array. I also start the indexing at 1 because we want our concatenation to happen late
s.Split(new string[] {"PEOPLE", "ENTERPRISE", ... }, StringSplitOptions.RemoveEmptyEntries);
And if you want save headers itself than possiblle it will be preferable to split your string multiple times by each arguments and add header by hands. For example you split your string by People and add people header to each chunk. Then split each chunk by HOME and add HOME header by hands and so on.
I'm going to give an answer that doesn't exactly match up with what you've asked for, so if you're dead set on having the output you've defined in your question then please disregard. Otherwise, I hope this is useful;
var peopleList = new List<string>();
var enterpriseList = new List<string>();
var homeList = new List<string>();
List<string> workingList = null;
using (var reader = new StreamReader("input.txt"))
{
string line = reader.ReadLine();
while (line != null)
{
switch (line)
{
case "PEOPLE": { workingList = peopleList; } break;
case "ENTERPRISE": { workingList = enterpriseList; } break;
case "HOME": { workingList = homeList; } break;
default: { workingList.Add(line); } break;
}
line = reader.ReadLine();
}
}
Based on your sample input, this will populate three lists as follows;
peopleList = { "John", "0218753458", "Vahn", "031245678" }
enterpriseList = { "stock", "30%", "Inc", "50%" }
homeList = { "Indiana", "West Virginia", "melbourne", "Australia" }