Regex to extract time information from a string [closed] - c#

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 3 years ago.
Improve this question
I'm receiving data from a third party device. I need to extract two pieces of information. I think I need to use a Regular Expression, but I don't know anything of this.
Below you can find a few example strings:
TN 12 1 17:45:19.90400 7173
TN 4 4 17:45:20.51800 7173
TN 13 1 17:45:24.03200 7173
TN 5 4 17:45:26.06300 7173
TN 6 4 17:45:29.28700 7173
TN 14 1 17:45:31.03200 7173
From each of these strings I need to extract two pieces of data:
the time
the number before the time
So the data I'm looking for is this:
1 and 17:45:19.90400
4 and 17:45:20.51800
1 and 17:45:24.03200
4 and 17:45:26.06300
4 and 17:45:29.28700
1 and 17:45:31.03200
The number will always be present and it will always be 1, 2, 3 or 4.
The time will also be the same format but I'm not sure if there will be single digit hours. So I don't know if 9 o'clock will be displayed as
9 or 09
Any suggestions on how I can extract this using a RegEx?
Thanks

My usual approach to this is to create a class that represents the data we want to capture, and give it a static Parse method that takes in an input string and returns an instance of the class populated with data from the string. Then we can just loop through the lines and populate a list of our custom class with data from each line.
For example:
class TimeData
{
public TimeSpan Time { get; set; }
public int Number { get; set; }
public static TimeData Parse(string input)
{
var timeData = new TimeData();
int number;
TimeSpan time;
if (string.IsNullOrWhiteSpace(input)) return timeData;
var parts = input.Split(new char[0], StringSplitOptions.RemoveEmptyEntries);
if (parts.Length > 2 && int.TryParse(parts[2], out number))
{
timeData.Number = number;
}
if (parts.Length > 3 && TimeSpan.TryParseExact(parts[3], "hh\\:mm\\:ss\\.fffff",
CultureInfo.CurrentCulture, out time))
{
timeData.Time = time;
}
return timeData;
}
}
Now we can just loop through the list of strings, call Parse on each line, and end up with a new list of objects that contain the Time and associated Number for each line. Also note that, by using a TimeSpan to represent the time, we now have properties for all the parts, like Hour, Minute, Seconds, Milliseconds, TotalMinutes, etc:
var fileLines = new List<string>
{
"TN 12 1 17:45:19.90400 7173",
"TN 4 4 17:45:20.51800 7173",
"TN 13 1 17:45:24.03200 7173",
"TN 5 4 17:45:26.06300 7173",
"TN 6 4 17:45:29.28700 7173",
"TN 14 1 17:45:31.03200 7173",
};
List<TimeData> allTimeData = fileLines.Select(TimeData.Parse).ToList();

Related

c# deleting the 0s of an int, but not if it is 20 [duplicate]

This question already has answers here:
How to remove leading zeros using C#
(9 answers)
Closed 5 years ago.
In my string start can be all sorts of numbers (1 until 99), but when the numbers get generated, 1 always get shown like 01. Is there an way to remove that 0, without if the number is 20 that the number get changed to 2?
You can use the String.TrimStart method:
string num = "0001";
num = num.TrimStart('0');
Another solution:
if (start.ElementAt(0) == '0')
start = start.Remove(0, 1);
or shorter:
start = start.ElementAt(0) == '0' ? start.Substring(1) : start;

Extracting text from the middle of a string [closed]

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 the following string that is captured from the DVLA when looking up a car registration details and I need to be able to extract just the numbers from the CC.
"A5 S LINE BLACK EDITION PLUS TDI 190 (2 DOOR), 1968cc, 2015 -
PRESENT"
Given that the lentgh of the string can change, is there a way to do this with a sub-string so for example always grab the numbers from before the cc without the space that comes before it? Bare in mind too that this can sometimes be a 3 digit number or a four digit number.
This does the trick:
string input = "A5 S LINE BLACK EDITION PLUS TDI 190 (2 DOOR), 1968cc, 2015 - PRESENT";
string size;
Regex r = new Regex("(\\d*)cc", RegexOptions.IgnoreCase);
Match m = r.Match(input);
if (m.Success)
{
size = m.Groups[0];
}
It captures every number that is right before cc
If the count of the comma doesn't change you can do following:
string s = "A5 S LINE BLACK EDITION PLUS TDI 190 (2 DOOR), 1968cc, 2015 - PRESENT";
string ccString = s.Split(',').ToList().Find(x => x.EndsWith("cc")).Trim();
int cc = Int32.Parse(ccString.Substring(0, ccString.Length - 2));
You can use Regex to match a pattern withing the string - so you can return parts of the string that match the given pattern. This Regex pattern will attempt to match parts of the string that fit the following pattern:
\d{1,5} *[cC]{2}
Starts with 1 to 5 digits \d{1,5} (seems sensible for an engine cc value!)
Can then contain 0 or more spaces in between that and cc *
Ends with any combination of 2 C or c [cC]{2}
So you can then use this in the following manner:
string str = "A5 S LINE BLACK EDITION PLUS TDI 190 (2 DOOR), 1968cc, 2015 - PRESENT";
Match result = Regex.Match(str, #"\d{1,5} *[cC]{2}");
string cc = result.Value; // 1968cc
Here is another solution:
string text = "A5 S LINE BLACK EDITION PLUS TDI 190 (2 DOOR), 1968cc, 2015 - PRESENT";
string[] substrings = text.Split(',');
string numeric = new String(substrings[1].Where(Char.IsDigit).ToArray());
Console.WriteLine(numeric);
Here is a working DEMO

How to use classes appropriately in this example? [closed]

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
1. Add an entry to the book.
Command syntax: add firstName lastName month day year Each entry in the birthday book consists of a first name, a last name, and a date. A date consists of a month, a day, and a year. You do not need to verify that the month, day, and year are sensible values. You may NOT assume that the month, day, and year are given as integers, and you must require the user to give you integers. Example ("> " is the prompt):
> add Natalie Hershlag 6 9 1981
Added "Natalie Hershlag, 6/9/1981" to birthday book.
> add William Pitt 12 18 1963
Added "William Pitt, 12/18/1963" to birthday book.
> add John Depp 6 9 1963
Added "John Depp, 6/9/1963" to birthday book.
> add Bono
Error: unable to add birthday to book. Add requires 5 arguments.
> add Paul Hewson May 10 1960
Error: unable to add birthday to book. Please use integers for dates.
2. List all entries in the book.
Command syntax: list
Prints out a list of all birthday book entries, numbered, one per line. Example:
> list
1. Madonna Ciccone, 8/16/1958
2. Natalie Hershlag, 6/9/1981
3. William Pitt, 12/18/1963
4. John Depp, 6/9/1963
3. Delete an entry in the book by number.
Command syntax: delete number
You may NOT assume that the user will always give an integer as the number that they want to delete. After
checking to see that the entry number is valid, the program should verify that the user really wants to delete the
entry by asking for a "y" or a "n", which mean "yes" or "no" respectively. You should continue to prompt for a
"y" or a "n" until you get one or the other. Example:
> list
1. Madonna Ciccone, 8/16/1958
2. Natalie Hershlag, 6/9/1981
3. William Pitt, 12/18/1963
4. John Depp, 6/9/1963
> delete 3
Really delete William Pitt from the birthday book? (y/n) y
> list
1. Madonna Ciccone, 8/16/1958
2. Natalie Hershlag, 6/9/1981
3. John Depp, 6/9/1963
> delete 4
I'm sorry, but there is no such entry in the book.
> delete 1
Really delete Madonna Ciccone from the birthday book? (y/n) nada
Please enter "y" or "n". (y/n) n
> list
1. Madonna Ciccone, 8/16/1958
2. Natalie Hershlag, 6/9/1981
3. John Depp, 6/9/1963
How would I go about starting this question? I need to incorporate the use of classes as well? I don't need specific code, but rather a general point on how to start this.
Would I start by putting each function (add, list, delete) into a different class to deal with them and having a common array in the main class?
In the spirit of helping, I'll give you a starting point:
Console.ReadLine <-- gives you inputs from what they typed in
You will need some classes, for example:
public class Person {
public string FirstName;
public string LastName;
public Date BirthDate;
}
Then you're going to want to have a main class that does some sort of printing with lines like
Console.WriteLine("Gimme stuffs");
and maybe even some
foreach(var p in People){
Console.WriteLine("Found person {0} {1}, {2}",p.FirstName, p.LastName, p.BirthDate);
}
and somewhere in that main class you'll have something like
List<Person> People = new List<Person>();
Validation:
I would make some sort of a thing like:
public static Person GetPerson(string str){
var all = str.Split(' ');
var p = new Person();
p.FirstName = all[0];
p.LastName = all[1];
int month = (int)all[2];
int day = (int)all[3];
int year = (int)all[4];
p.BirthDate = new Date(year,month,day);
return p;
}
and for a fast validation:
if(str.Split(' ').Length != 5) //you don't have a valid input line
but then also
int testInt = 0;
if(!int.TryParse(str.Split(' ')[3], out testInt)) //you don't have a valid month
Now, that's a lot of help. Go forth and TRY FOR YOURSELF.

Convert a string to multidimensional array

I have a matrix, which is read from the console. The elements are separated by spaces and new lines. How can I convert it into a multidimensional int array in c#? I have tried:
String[][] matrix = (Console.ReadLine()).Split( '\n' ).Select( t => t.Split( ' ' ) ).ToArray();
but when I click enter, the program ends and it doesn't allow me to enter more lines.
The example is:
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
5 6 7 8 9
int[,] Matrix = new int[n_rows,n_columns];
for(int i=0;i<n_rows;i++){
String input=Console.ReadLine();
String[] inputs=input.Split(' ');
for(int j=0;j<n_columns;j++){
Matrix[i,j]=Convert.ToInt32(inputs[j]);
}
}
you can try this to load the matrix
First things first, Console.ReadLine() reads a single line from the input. So in order to accept multiple lines you need to do 2 things:
Have a loop which allows the user to continue entering lines of data. You could let them go until they leave a line blank, or you could fix it to 5 lines of input
Store these "lines" of data for future processing.
Assuming the user can enter any number of lines, and a blank line (just hitting enter) indicates the end of data entry something like this will suffice
List<string> inputs = new List<string>();
var endInput = false;
while(!endInput)
{
var currentInput = Console.ReadLine();
if(String.IsNullOrWhitespace(currentInput))
{
endInput = true;
}
else
{
inputs.Add(currentInput);
}
}
// when code continues here you have all the user's input in separate entries in "inputs"
Now for turning that into an array of arrays:
var result = inputs.Select(i => i.Split(' ').ToArray()).ToArray();
That will give you an array of arrays of strings (which is what your example had). If you wanted these to be integers you could parse them as you go:
var result = inputs.Select(i => i.Split(' ').Select(v => int.Parse(v)).ToArray()).ToArray();
// incoming single-string matrix:
String input = #"1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
5 6 7 8 9";
// processing:
String[][] result = input
// Divide in to rows by \n or \r (but remove empty entries)
.Split(new[]{ '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries)
// no divide each row into columns based on spaces
.Select(x => x.Split(new[]{ ' ' }, StringSplitOptions.RemoveEmptyEntries))
// case from IEnumerable<String[]> to String[][]
.ToArray();
result:
String[][] result = new string[]{
new string[]{ "1","2","3","4","5" },
new string[]{ "2","3","4","5","6" },
new string[]{ "3","4","5","6","7" },
new string[]{ "4","5","6","7","8" },
new string[]{ "5","6","7","8","9" }
};
It can be done in multiple ways
You can read a single line containing multiple numbers separated by a char, split by that char obtaining an array of ints and then you should fetch a matrix.
With out-of-the-box linq there is no trivial way for the fetching step and i think it is not really the case to use third-party libraries from codeplex like LinqLib or something.

Best way to Find which cell of string array contins text

I have a block of text that im taking from a Gedcom (Here and Here) File
The text is flat and basically broken into "nodes"
I am splitting each node on the \r char and thus subdividing it into each of its parts( amount of "lines" can vary)
I know the 0 address will always be the ID but after that everything can be anywhere so i want to test each Cell of the array to see if it contains the correct tag for me to proccess
an example of what two nodes would look like
0 #ind23815# INDI <<<<<<<<<<<<<<<<<<< Start of node 1
1 NAME Lawrence /Hucstepe/
2 DISPLAY Lawrence Hucstepe
2 GIVN Lawrence
2 SURN Hucstepe
1 POSITION -850,-210
2 BOUNDARY_RECT (-887,-177),(-813,-257)
1 SEX M
1 BIRT
2 DATE 1521
1 DEAT Y
2 DATE 1559
1 NOTE * Born: Abt 1521, Kent, England
2 CONT * Marriage: Jane Pope 17 Aug 1546, Kent, England
2 CONT * Died: Bef 1559, Kent, England
2 CONT
1 FAMS #fam08318#
0 #ind23816# INDI <<<<<<<<<<<<<<<<<<<<<<< Start of Node 2
1 NAME Jane /Pope/
2 DISPLAY Jane Pope
2 GIVN Jane
2 SURN Pope
1 POSITION -750,-210
2 BOUNDARY_RECT (-787,-177),(-713,-257)
1 SEX F
1 BIRT
2 DATE 1525
1 DEAT Y
2 DATE 1609
1 NOTE * Born: Abt 1525, Tenterden, Kent, England
2 CONT * Marriage: Lawrence Hucstepe 17 Aug 1546, Kent, England
2 CONT * Died: 23 Oct 1609
2 CONT
1 FAMS #fam08318#
0 #ind23817# INDI <<<<<<<<<<< start of Node 3
So a when im done i have an array that looks like
address , string
0 = "1 NAME Lawrence /Hucstepe/"
1 = "2 DISPLAY Lawrence Hucstepe"
2 = "2 GIVN Lawrence"
3 = "2 SURN Hucstepe"
4 = "1 POSITION -850,-210"
5 = "2 BOUNDARY_RECT (-887,-177),(-813,-257)"
6 = "1 SEX M"
7 = "1 BIRT "
8 = "1 FAMS #fam08318#"
So my question is what is the best way to search the above array to see which Cell has the SEX tag or the NAME Tag or the FAMS Tag
this is the code i have
private int FindIndexinArray(string[] Arr, string search)
{
int Val = -1;
for (int i = 0; i < Arr.Length; i++)
{
if (Arr[i].Contains(search))
{
Val = i;
}
}
return Val;
}
But it seems inefficient because i end up calling it twice to make sure it doesnt return a -1
Like so
if (FindIndexinArray(SubNode, "1 BIRT ") != -1)
{
// add birthday to Struct
I.BirthDay = SubNode[FindIndexinArray(SubNode, "1 BIRT ") + 1].Replace("2 DATE ", "").Trim();
}
sorry this is a longer post but hopefully you guys will have some expert advice
Can use the static method FindAll of the Array class:
It will return the string itself though, if that works..
string[] test = { "Sex", "Love", "Rock and Roll", "Drugs", "Computer"};
Array.FindAll(test, item => item.Contains("Sex") || item.Contains("Drugs") || item.Contains("Computer"));
The => indicates a lamda expression. Basically a method without a concrete implementation.
You can also do this if the lamda gives you the creeps.
//Declare a method
private bool HasTag(string s)
{
return s.Contains("Sex") || s.Contains("Drugs") || s.Contains("Computer");
}
string[] test = { "Sex", "Love", "Rock and Roll", "Drugs", "Computer"};
Array.FindAll(test, HasTag);
What about a simple regular expression?
^(\d)\s=\s\"\d\s(SEX|BIRT|FAMS){1}.*$
First group captures the address, second group the tag.
Also, it might be quicker to dump all array items into a string and do your regex on the whole lot at once.
"But it seems inefficient because i end up calling it twice to make sure it doesnt return a -1"
Copy the returned value to a variable before you test to prevent multiple calls.
IndexResults = FindIndexinArray(SubNode, "1 BIRT ")
if (IndexResults != -1)
{
// add birthday to Struct
I.BirthDay = SubNode[IndexResults].Replace("2 DATE ", "").Trim();
}
The for loop in method FindIndexinArray shd break once you find a match if you are interested in only the first match.

Categories

Resources