Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I have to parse this string
"Cust =Customer CustCR =Customer Credit Prod=Product SalesRep=Sales Rep TaxCat=Tax Category TaxId=Tax ID VolBill=Volume Billing"
as Code, Description like Code=Cust and Description=Customer
split on basis of space is not working for this because there is also a space in description too .
Instead of splitting on space you can split on the equals sign. Then the code will be the value after the last space of the previous item and the description will be everything up to the last space making sure to trim the spaces that might show up before the equals. And you can replace the Dictionary with whatever data type you want to load the values into. Also you have to handle the first and last values as special cases. Note this will only work if the codes do not contain spaces.
string str = "Cust =Customer CustCR =Customer Credit Prod=Product SalesRep=Sales Rep TaxCat=Tax Category TaxId=Tax ID VolBill=Volume Billing";
var separated = str.Split('=');
string code = separated[0].Trim();
var codeAndDescription = new Dictionary<string, string>();
for (int i = 1; i < separated.Length - 1; i++)
{
int lastSpace = separated[i].Trim().LastIndexOf(' ');
var description = separated[i].Substring(0, lastSpace).Trim();
codeAndDescription.Add(code, description);
code = separated[i].Substring(lastSpace + 1).Trim();
}
codeAndDescription.Add(code, separated[separated.Length - 1]);
foreach (var kvp in codeAndDescription)
Console.WriteLine(kvp);
Outputs
[Cust, Customer]
[CustCR, Customer Credit]
[Prod, Product]
[SalesRep, Sales Rep]
[TaxCat, Tax Category]
[TaxId, Tax ID]
[VolBill, Volume Billing]
A little modification for another case if description is empty, also used custom Item class to store output in a list
class Item {
public string Code { get; set; }
public string Description { get; set; }
}
class Program
{
static void Main(string[] args)
{
string str = "0= 1=Full Time 2=Part Time 3=Seasonal 4=Variable";
var separated = str.Split('=');
string code = separated[0].Trim();
var codeAndDescription = new List<Item>();
foreach (var sep in separated.Skip(1).Take(separated.Length - 2))
{
int lastSpace = sep.Trim().LastIndexOf(' ');
var description = lastSpace != -1 ? sep.Substring(0, lastSpace).Trim(): "" ;
codeAndDescription.Add(new Item { Code=code,Description=description });
code = sep.Substring(lastSpace + 1).Trim();
}
codeAndDescription.Add(new Item { Code = code, Description = separated.Last() });
foreach (var kvp in codeAndDescription)
{
Console.WriteLine("Code={0} Description={1}", kvp.Code, kvp.Description);
}
Console.ReadLine();
}
}
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
In C# I am passing a single string value to a function. The value is similar to this: "XA=12345678;BK=AZ31" or "XA=87654321", sometimes the BK= is there, sometimes it is not. But if it's present, I need it for my function.
I've made this attempt:
string[] item_list = { "XA=12345678;BK=AZ31", "XA=87654321" };
string XA_EQ = "";
string BK_EQ = "";
foreach(string item in item_list)
{
BK_EQ = "";
string[] split = item.Split(';');
XA_EQ = split[0];
if(split.length == 2)
BK_EQ = split[1];
my_func(XA_EQ, BK_EQ);
}
Is there a better way to do this? This works, but it seems inconvenient.
RegEx approach
string[] item_list = { "XA=12345678;BK=AZ31", "XA=87654321" };
foreach (string item in item_list)
{
string XA_EQ = Regex.Match(item, "(?<=XA=)[0-9A-Z]*").Value;
string BK_EQ = Regex.Match(item, "(?<=BK=)[0-9A-Z]*").Value;
my_func(XA_EQ, BK_EQ);
}
https://dotnetfiddle.net/6xgBi3
I suggest Splitting initial strings into Dictionary:
using System.Linq;
...
private static Dictionary<string, string> GetVariables(string source) {
return source
.Split(';')
.Select(pair => pair.Split('='))
.ToDictionary(pair => pair[0].Trim(), pair => pair[1].Trim());
}
Now we can analyze values:
string[] item_list = new string[] { "XA=12345678;BK=AZ31", "XA=87654321" };
foreach(string item in item_list) {
var namesAndValues = GetVariables(item);
// If we have XA variable, assign its value to XA_EQ, otherwise assign ""
string XA_EQ = namesAndValues.TryGetValue("XA", out string xa) ? xa : "";
// If we have "BK" variable, call my_func with it
if (namesAndValues.TryGetValue("BK", out string BK_EQ)) {
// If we have "BK" variable
my_func(XA_EQ, BK_EQ);
}
}
Easy to read solution with LINQ:
string[] itemList = { "XA=12345678;BK=AZ31", "XA=87654321" };
itemList.Select(x => x.Split(";")).ToList().ForEach(i =>
{
string XA_EQ = i.FirstOrDefault();
string BK_EQ = i.Skip(1).FirstOrDefault();
my_func(XA_EQ, BK_EQ != null ? BK_EQ : "");
});
You don't get the actual value of XA or BK this way, but since you mention that this works for you I'm implementing the same logic.
string[] item_list = { "XA=12345678;BK=AZ31", "XA=87654321" };
foreach(string item in item_list)
{
if item.Contains('BK') {
string[] split = item.split(';');
my_func(split[0], split[1]);
} else {
my_func(item, null);
}
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I have text file like this:
VehicleReferenceKey:2365565656
DriverReferenceKey:965454545454
Latitude:30000
**
VehicleReferenceKey:96896A4607A6
DriverReferenceKey:96896A4607A6
Latitude:500
**
VehicleReferenceKey:822F5B18
DriverReferenceKey:822F5B18
Latitude:1000
I try To convert this text file to Excel
first i made an Class as
public class Item
{
public string VehicleReferenceKey;
public string DriverReferenceKey;
public string Latitude;
}
then i read all text file and looping of it as
var lines = File.ReadAllLines(fileName);
for (var i = 0; i < lines.Length; i += 1) {
var line = lines[i];
// Process line
}
but I Can't determine how i can specify the Key and value
for each line , and how tell the sign
**
as it's breaker between each object .Any Help
Try following code :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication87
{
class Program
{
const string FILENAME = #"c:\temp\test.txt";
static void Main(string[] args)
{
Item items = new Item(FILENAME);
}
}
public class Item
{
public static List<Item> items = new List<Item>();
public string VehicleReferenceKey;
public string DriverReferenceKey;
public string Latitude;
public Item() { }
public Item(string filenam)
{
StreamReader reader = new StreamReader(filenam);
string line = "";
Item newItem = null;
while ((line = reader.ReadLine()) != null)
{
line = line.Trim();
if (line.Length > 0)
{
string[] rowItems = line.Split(new char[] { ':' });
switch (rowItems[0])
{
case "VehicleReferenceKey" :
newItem = new Item();
items.Add(newItem);
newItem.VehicleReferenceKey = rowItems[1];
break;
case "DriverReferenceKey":
newItem.DriverReferenceKey = rowItems[1];
break;
case "Latitude":
newItem.Latitude = rowItems[1];
break;
}
}
}
}
}
}
Basically it seems the following hold for your file:
The first item takes 3 lines (one for each field)
Every item after the first takes 7 lines (2 empty lines, 1 line containing "**", 1 empty line and then the 3 lines with the field values)
So there's no reason to parse the ** and the empty lines you can just skip those (by looping over 7 lines at a time).
For the seperating key and value you can use the String.Split method.
All in all it would look something like this:
for (var i = 0; i < lines.Length + 2; i += 7)
{
var newItem = new Item(){
VehicleReferenceKey = lines[i].Split(':')[1],
DriverReferenceKey = lines[i+1].Split(':')[1],
Latitude = lines[i+2].Split(':')[1]
}
//do whatever you want with the newItem
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I have this text file that only has one row. Each file contains one customer name but multiple items and descriptions.
Record starting with 00 (Company Name) has a char length of 10
01 (Item#) - char length of 10
02 (Description) - char length of 50
I know how to read a file, but I don't have any idea of how to loop through only one line, find records 00, 01, 02 and grab the text based on the length, finally start at the position of the last records and start the loop again. Can someone please give me an idea of how to read files like this?
output:
companyName 16622 Description
companyName 15522 Description
input text file example
00Init 0115522 02Description 0116622 02Description
This solution assumes that the data is fixed width, and that item number will preceed description (01 before 02). This solution will emit a record every time a description record is encountered, and deals with multiple products for the same company.
First, define a class to hold your data:
public class Record
{
public string CompanyName { get; set; }
public string ItemNumber { get; set; }
public string Description { get; set; }
}
Then, iterate through your string, returning a record when you've got a description:
public static IEnumerable<Record> ReadFile(string input)
{
// Alter these as appropriate
const int RECORDTYPELENGTH = 2;
const int COMPANYNAMELENGTH = 41;
const int ITEMNUMBERLENGTH = 8;
const int DESCRIPTIONLENGTH = 48;
int index = 0;
string companyName = null;
string itemNumber = null;
while (index < input.Length)
{
string recordType = input.Substring(index, RECORDTYPELENGTH);
index += RECORDTYPELENGTH;
if (recordType == "00")
{
companyName = input.Substring(index, COMPANYNAMELENGTH).Trim();
index += COMPANYNAMELENGTH;
}
else if (recordType == "01")
{
itemNumber = input.Substring(index, ITEMNUMBERLENGTH).Trim();
index += ITEMNUMBERLENGTH;
}
else if (recordType == "02")
{
string description = input.Substring(index, DESCRIPTIONLENGTH).Trim();
index += DESCRIPTIONLENGTH;
yield return new Record
{
CompanyName = companyName,
ItemNumber = itemNumber,
Description = description
};
}
else
{
throw new FormatException("Unexpected record type " + recordType);
}
}
}
Note that your field lengths in the question don't match the sample data, so I adjusted them so that the solution worked with the data you provided. You can adjust the field lengths by adjusting the constants.
Use this like the following:
string input = "00CompanyName 0115522 02Description 0116622 02Description ";
foreach (var record in ReadFile(input))
{
Console.WriteLine("{0}\t{1}\t{2}", record.CompanyName, record.ItemNumber, record.Description);
}
If you read the whole file into a string, you have a couple options.
One, it might be useful to use string.split.
Another option would be to use string.indexof. Once you have the index, you could use string.substring
Assuming fixed-width as specified, lets create two simple classes to hold a client and its related data as a list:
// can hold as many items (data) as there are in the line
public class Client
{
public string name;
public List<ClientData> data;
};
// one single item in the client data
public class ClientData
{
public string code;
public string description;
};
To parse a single line (which is assumed to have a single client and a successive list of item/description), we can do this (note: for simplification I'm just creating a static class with a static method in it):
// this parser will read as many itens as there are in the line
// and return a Client instance with those inside.
public static class Parser
{
public static Client ParseData(string line)
{
Client client = new Client ();
client.data = new List<ClientData> ();
client.name = line.Substring (2, 10);
// remove the client name
line = line.Substring (12);
while (line.Length > 0)
{
// create new item
ClientData data = new ClientData ();
data.code = line.Substring (2, 10);
data.description = line.Substring (14, 50);
client.data.Add (data);
// next item
line = line.Substring (64);
}
return client;
}
}
So, in your main loop, just after reading a new line from the file, you can call the above method to receive a new client. Something like this:
// should be from a file but this is just an example
string[] lines = {
"00XXXXXXXXXX01YYYYYYYYYY02XXXXXXXXX.XXXXXXXXX.XXXXXXXXX.XXXXXXXXX.XXXXXXXXXX",
"00XXXXXXXXXX01YYYYYYYYYY02XXXXXXXXX.XXXXXXXXX.XXXXXXXXX.XXXXXXXXX.XXXXXXXXXX01YYYYYYYYYY02XXXXXXXXX.XXXXXXXXX.XXXXXXXXX.XXXXXXXXX.XXXXXXXXXX",
"00XXXXXXXXXX01YYYYYYYYYY02XXXXXXXXX.XXXXXXXXX.XXXXXXXXX.XXXXXXXXX.XXXXXXXXXX",
"00XXXXXXXXXX01YYYYYYYYYY02XXXXXXXXX.XXXXXXXXX.XXXXXXXXX.XXXXXXXXX.XXXXXXXXXX",
"00XXXXXXXXXX01YYYYYYYYYY02XXXXXXXXX.XXXXXXXXX.XXXXXXXXX.XXXXXXXXX.XXXXXXXXXX",
};
// loop through each line
// (lines can have multiple items)
foreach (string line in lines)
{
Client client = Parser.ParseData (line);
Console.WriteLine ("Read: " + client.name);
}
Contents of Sample.txt:
00Company1 0115522 02This is a description for company 1. 00Company2 0115523 02This is a description for company 2. 00Company3 0115524 02This is a description for company 3
Note that in the code below, the fields are 2 characters longer than those specified in the original question. This is because I am including the headings in the length of each field, thus a field of a length of 10is effectively 12 by including the 00 from the heading. If this is undesirable, tweak the offsets of the entries in the fieldLengths array.
String directory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
String file = "Sample.txt";
String path = Path.Combine(directory, file);
Int32[] fieldLengths = new Int32[] { 12, 12, 52 };
List<RowData> rows = new List<RowData>();
Byte[] buffer = new Byte[fieldLengths.Sum()];
using (var stream = File.OpenRead(path))
{
while (stream.Read(buffer, 0, buffer.Length) > 0)
{
List<String> fieldValues = new List<String>();
Int32 offset = 0;
for (int i = 0; i < fieldLengths.Length; i++)
{
var value = Encoding.UTF8.GetString(buffer, offset, fieldLengths[i]);
fieldValues.Add(value);
offset += fieldLengths[i];
}
String companyName = fieldValues[0];
String itemNumber = fieldValues[1];
String description = fieldValues[2];
var row = new RowData(companyName, itemNumber, description);
rows.Add(row);
}
}
Class definition for RowData:
public class RowData
{
public String Company { get; set; }
public String Number { get; set; }
public String Description { get; set; }
public RowData(String company, String number, String description)
{
Company = company;
Number = number;
Description = description;
}
}
The results will be in the rows variable.
You would have to split rows based on a delimiter. It would seem that in your case you are using whitespace as a delimiter.
The method you are looking for is String.Split(), it should cover your needs :) Documentation is located at https://msdn.microsoft.com/en-us/library/system.string.split(v=vs.110).aspx - It also includes examples.
I'd do something like this:
string myLineOfText = "MyCompany 12345 The description of my company";
string[] partsOfMyLine = myLineOfText.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
Best of luck! :)
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I'm creating a search similar to the one at yp.com where I need to parse the city name and state name from a text box. City can be multiple words and state can be a full name or abbreviation. There may be a comma between city and state but there also might not be.
Examples:
Grand Rapids, New Mexico
Grand Rapids New Mexico
Grand Rapids, NM
Grand Rapids NM
This is pretty easy to do if there is a comma involved but I'm not sure at all how to do this if there is no comma.
Try this code:
class Program
{
static void Main(string[] args)
{
PrintCityState(GetCityState("Grand Rapids, New Mexico"));
PrintCityState(GetCityState("Sacremento California"));
PrintCityState(GetCityState("Indianpolis, IN"));
PrintCityState(GetCityState("Phoenix AZ"));
}
public static void PrintCityState(CityState cs)
{
Console.WriteLine("{0}, {1} ({2})", cs.City, cs.StateAbbreviation, cs.StateName);
}
public static CityState GetCityState(string input)
{
string truncatedInput = input;
var statesDictionary = new Dictionary<string, string>
{
{"AZ", "Arizona"},
{"NM", "New Mexico"},
{"CA", "California"},
{"WA", "Washington"},
{"OR", "Oregon"},
{"MI", "Michigan"},
{"IN", "Indiana"}
// And so forth for all 50 states
};
var cityState = new CityState();
foreach (KeyValuePair<string, string> kvp in statesDictionary)
{
if (input.Trim().ToLower().EndsWith(" " + kvp.Key.ToLower()))
{
cityState.StateName = kvp.Value;
cityState.StateAbbreviation = kvp.Key;
truncatedInput = input.Remove(input.Length - 1 - kvp.Key.Length);
break;
}
if (input.Trim().ToLower().EndsWith(" " + kvp.Value.ToLower()))
{
cityState.StateName = kvp.Value;
cityState.StateAbbreviation = kvp.Key;
truncatedInput = input.Remove(input.Length - 1 - kvp.Value.Length);
break;
}
}
cityState.City = truncatedInput.Trim().Trim(',').Trim();
return cityState;
}
}
public class CityState
{
public string City { get; set; }
public string StateName { get; set; }
public string StateAbbreviation { get; set; }
}
This code uses a dictionary of state names and abbreviations. I only added 7 states for brevity, but you can add all 50. It searches the input string for a match on either the dictionary keys or dictionary values. If it finds one, it removes the state and whats left is the city.
Make sure you add West Virginia before Virginia in order for it to parse correctly.
It actually required more logic than I thought, but this should be working.
var entries = new List<string[]>(); // List of entries
foreach (var e in str.Split('\n')) // Splits by new line .. Can be modified to whatever ...
{
if (string.IsNullOrWhiteSpace(e) || !e.Contains(" ")) // If the string is empty, whitespace or doesn't contain a space
continue; // Skip to next line
string[] entry; // Entry holder ...
if (e.Contains(",")) // If the entry contains ","
{
entry = e.Split(','); // Split it by ,
entries.Add(new string[] { entry[1].Trim(), entry[0].Trim() }); // The two entries should be the state and city, so add it to the entries
continue; // Skip to next line
}
entry = e.Split(' '); // Splits the entry by space
if (entry.Length < 2) // If there is less than two entries
continue; // Skip to next line
if (entry.Length > 2) // Checks if there are more than two entries Ex. "Grand Rapids New Mexico"
{
var statePart1 = entry[entry.Length - 2]; // Gets the first part of the state
var statePart2 = entry[entry.Length - 1]; // Gets the second part of the state
// Note: statePart1 is invalid if the state only has one "word", statePart2 is valid in this case
if (statePart1 == "North" || statePart1 == "South" || statePart1 == "West" || statePart1 == "New") // Checks if statePart1 is valid
{
int stateSize = statePart1.Length + statePart2.Length + 2; // Gets the state string size
var state = string.Format("{0} {1}", statePart1, statePart2); // Creates the state string
var city = e.Substring(0, e.Length - stateSize); // Gets the city string
entries.Add(new string[] { state, city }); // Adds the entry to the entries
}
else
{
// If statePart1 is not valid then the state is a single "word"
int cityLength = e.LastIndexOf(' '); // Gets the length of the city
entries.Add(new string[] { statePart2, e.Substring(0, cityLength) }); // Adds the entry to the entries
}
}
else
{
// If there is only two entries then both the city and state has only one "word"
entries.Add(new string[] { entry[1], entry[0] }); // Adds the entry to the entries
}
}
You can use the entries like this after
foreach (var e in entries)
Console.WriteLine("{0}, {1}", e[0], e[1]);
Which could result in something like:
string str = #"Grand Rapids New Mexico
Grand Rapids, NM
New York City New York
Jacksonville Florida
Bismarck North Dakota
Las Vegas Nevada";
Output ...
New Mexico, Grand Rapids
NM, Grand Rapids
New York, New York City
Florida, Jacksonville
North Dakota, Bismarck
Nevada, Las Vegas
Of course this is assuming you're parsing American states / cities.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I need to get data from a list but orderly mer mean get in the order, but I have this code is not working out.
if (item is TextBoxUniversal)
{
foreach (string i in itemlist)
{
ItemValorEntity x = new ItemValorEntity();
x.Item_Id = i[itemIndex].ToString();
strItem = x.Item_Id;
itemIndex += 1;
}
txt.Name = item.Name;
txt = GetTexBox(txt.Name, groupBox1);
itemValor.Item_Id = strItem;
itemValor.cClave = Convert.ToString(cboGTTipoItems.SelectedValue);
itemValor.Valor = txt.Text;
}
In a list I have several items can be 101, 102, 103, etc.. I need to get them in order.
That code only managed to get 1 but is not is 1 is 101
Solucionado
if (item is TextBoxUniversal)
{
string _item = itemlist[itemIndex].ToString();
itemIndex++;
txt.Name = item.Name;
txt = GetTexBox(txt.Name, groupBox1);
itemValor.Item_Id = _item;
itemValor.cClave = Convert.ToString(cboGTTipoItems.SelectedValue);
itemValor.Valor = txt.Text;
}
Updated:
I removed previous answer as I believe this is more what you're looking for. The ability to sort a list that you've received. Your question is still poorly asked, so I'm going to go off some assumptions you've implied. Those are:
Utilize a hard-coded List.
Sort the List.
Display to a user.
The class you'll want to look at for the sort is List(T).Sort it provides a clean, quick, and simple approach to accomplish the goal. Details can be found here.
I'm going to use a more practical scenario, we have a series of students that will require their score / grades be sorted before output to our user.
To begin will build our Student object.
public class Student
{
public string Name { get; set; }
public int Score { get; set; }
public string Grade { get; set; }
}
So far our object is pretty simple, it contains:
Name (Who it is)
Actual score (Numeric Representation)
Grade (Letter Representation)
Now we will implement the IComparable<Student> to our Student object. This will implicitly implement the following method:
public int CompareTo(Student other)
{
throw new NotImplementedException();
}
So we will remove the Exception out of the method and implement:
if(other == null)
return 1;
else
return this.Score.CompareTo(other.Score);
This small amount of code will do the following:
If the object is null it will be greater.
It will compare our current Property to our Parameter Value.
Now all we have to do for our implementation:
// Create Our List
List<Student> student = new List<Student>();
// Add our Students to the List
student.Add(new Student() { Name = "Greg", Score = 100, Grade = "A+" });
student.Add(new Student() { Name = "Kelli", Score = 32, Grade = "F" });
student.Add(new Student() { Name = "Jon", Score = 95, Grade = "A" });
student.Add(new Student() { Name = "Tina", Score = 93, Grade = "A-" });
student.Add(new Student() { Name = "Erik", Score = 82, Grade = "B" });
student.Add(new Student() { Name = "Ashley", Score = 75, Grade = "C" });
// Apply our Sort.
student.Sort();
// Loop through Our List:
foreach (Student placement in student)
listBox1.Items.Add(placement.Name + " " + placement.Score + " " + placement.Grade);
That will put them in a Ascending order. You can tweak and configure to make it Descending should you require it, or even more complex. Hopefully this is a nice starting point.
Also some items have OrderBy or OrderByDescending accessible. So you can actually do code like this to a Dictionary.
student.OrderByDescending(s => s.Value);
You have a slew of possibilities, hopefully this gets you started and able to think about your implementation a bit.