I have a string of the format MASTER CARD 01/01/2012, I need to grab the date part separately.
Sometimes it could be VISA 01/01/2012, I have tried splitting by the space but got stuck when there are two spaces like in the case of MASTER CARD 01/01/2012.
Any help would be much appreciated;
string date = e.Brick.Text;
string[] dates = date.Split(' ');
The way your strings look, you will get the date in your last element in array.
//dates[dates.Length-1] should have date
string date = "MASTER CARD 01/01/2012";
string[] dates = date.Split(' ');
Console.WriteLine(dates[dates.Length - 1]);
A proper solution should be to check each item against DateTime, something on the following line
DateTime tempDs = new DateTime();
foreach (string str in dates)
{
if (DateTime.TryParse(str, out tempDs))
{
Console.WriteLine("Found Date");
}
}
Assuming all the dates for the various cards have similar formatting, Regular Expressions could be a viable alternative.
using System.Text.RegularExpressions;
Match mDate = Regex.Match(e.Brick.Text, #"\b(?<date>(?:\d{1,2}[\\/-]){2}\d{4})\b", RegexOptions.Compiled);
if (mDate.Success)
{
MessageBox.Show(string.Format("Date: {0}", mDate.Groups["date"].Value));
}
Split by spaces and use the DateTime.TryParse method to parse the dates. The method should fail for VISA, MASTER, and CARD; but it will succeed for the date parts of the string.
You can use your code.
If the date is always at the end of the string you can do something like
year = dates[dates.Length-1]
And so on for month and day
Here is another alternative:
string date = e.Brick.Text.Substring(e.Brick.Text.LastIndexOf(' ')+1);
This should do the trick.
public string ExtractDateTimeString(string s){
return s.Split(' ').Where(x =>
{
DateTime o;
return DateTime.TryParse(x, out o);
}).FirstOrDefault();
}
Or another way:
string text = "MASTER CARD 4.5.2012";
string[] split = text.Split(' ');
string mc = "";
string date = ""; //when you get this value, you can easily convert to date if you need it
foreach (string str in split)
{
if (char.IsNumber(str[0]))
{
date = str;
mc = mc.Remove(mc.Length - 1, 1);
}
else
mc += str + " ";
}
Related
Hello Please could you suggest better ways of writing this C# code.
Basically when NumberList has missing values between '-' I am trying to rebuild the String with default Values.
The final result should be "123-10-45-9-09"
As you can see value of "second-10" is replaced as the second item in the string.
10, 9 and 09 are filled in from the value string values.
This is the bad string which is missing some values.
string NumberList = "123--45--";
I have stored this string value in my app.config file.
string valuestring = "first-12,second-10,third-99,fourth-9,fifth-09";
protected string MissingNumberString(string Number)
{
string NumberList = "123--45--";
string valuestring = "first-12,second-10,third-99,fourth-9,fifth-09";
var companyAccountList = valuestring.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
var result = NumberList.Split('-');
int counter = 0;
var builder = new System.Text.StringBuilder();
foreach (string s in companyAccountList)
{
string t = s.Substring(s.IndexOf('-') + 1);
if (string.IsNullOrEmpty(result[counter]))
builder.Append(t).Append("-");
else
{
if (companyAccountList.Length == counter)
builder.Append(result[counter]);
else
builder.Append(result[counter]).Append("-");
}
counter++;
}
return builder.ToString();
}
One way (assuming valuestring is in order and do not miss any defaults) to achieve this would be
string MissingNumber(string Number)
{
string valuestring = "first-12,second-10,third-99,fourth-9,fifth-09";
var regex = Regex.Matches(valuestring,#"(?<=-)(\d*)(?<=,)?");
var defaults = regex.Cast<Match>().Select(x=>x.Value).ToList();
var newArray = Number.Split('-').Select((x,index)=>string.IsNullOrEmpty(x)?defaults[index]:x);
return string.Join("-",newArray);
}
The code uses Regular Expression to break the ValueString and read the default values.
Regex.Matches(valuestring,#"(?<=-)(\d*)(?<=,)?");
The regular expression uses non-capturing groups to capture a number which is prefixed as by an optional "-" character and suffixed by an optional "," character.
Once the defaults are parsed into a List (assuming that the positions are in order and do not miss any values), we loop through the input string (which has been split based on delimiter), check if it is Empty, and if so, use the value from the Defaults (based on our assumption, it should have same index).
Update
Based on the comments, it looks like you other data in the original string, and hence the concerned sub-string has to be captured first.
We could update the Missing Number method as
static string MissingNumber(string Number)
{
string valuestring = "first-12,second-10,third-99,fourth-9,fifth-09";
var regexDefaultValues = Regex.Matches(valuestring,#"(?<=-)(\d*)(?<=,)?");
var defaults = regexDefaultValues.Cast<Match>().Select(x=>x.Value).ToList();
var regexNumberToParse = new Regex(#"(\d)*-(\d)*-(\d)*-(\d)*-(\d)*");
var capturedNumberFormat = regexNumberToParse.Match(Number).Value;
var newArray = capturedNumberFormat.Split('-').Select((x,index)=>string.IsNullOrEmpty(x)?defaults[index]:x);
var ValueWithDefaults = string.Join("-",newArray);
return regexNumberToParse.Replace(Number,ValueWithDefaults);
}
Demo Code
I have these data files comming in on a server that i need to split into [date time] and [value]. Most of them are delimited a single time between time and value and between date and time is a space. I already have a program processing the data with a simple split(char[]) but now found data where the delimiter is a space and i am wondering how to tackle this best.
So most files i encountered look like this:
18-06-2014 12:00:00|220.6
The delimiters vary, but i tackled that with a char[]. But today i ran into a problem on this format:
18-06-2014 12:00:00 220.6
This complicates things a little. The easy solution would be to just add a space to my split characters and when i find 3 splits combine the first two before processing?
I'm looking for a 2nd opining on this matter. Also the time format can change to something like d/m/yy and the amount of lines can run into the millions so i would like to keep it as efficient as possible.
Yes I believe the most efficient solution is to add space as a delimiter and then just combine the first two if you get three. That is going to be be more efficient than regex.
You've got a string 18-06-2014 12:00:00 220.6 where first 19 characters is a date, one character is a separation symbol and other characters is a value. So:
var test = "18-06-2014 12:00:00|220.6";
var dateString = test.Remove(19);
var val = test.Substring(20);
Added normalization:
static void Main(string[] args) {
var test = "18-06-2014 12:00:00|220.6";
var test2 = "18-6-14 12:00:00|220.6";
var test3 = "8-06-14 12:00:00|220.6";
Console.WriteLine(test);
Console.WriteLine(TryNormalizeImportValue(test));
Console.WriteLine(test2);
Console.WriteLine(TryNormalizeImportValue(test2));
Console.WriteLine(test3);
Console.WriteLine(TryNormalizeImportValue(test3));
}
private static string TryNormalizeImportValue(string value) {
var valueSplittedByDateSeparator = value.Split('-');
if (valueSplittedByDateSeparator.Length < 3) throw new InvalidDataException();
var normalizedDay = NormalizeImportDayValue(valueSplittedByDateSeparator[0]);
var normalizedMonth = NormalizeImportMonthValue(valueSplittedByDateSeparator[1]);
var valueYearPartSplittedByDateTimeSeparator = valueSplittedByDateSeparator[2].Split(' ');
if (valueYearPartSplittedByDateTimeSeparator.Length < 2) throw new InvalidDataException();
var normalizedYear = NormalizeImportYearValue(valueYearPartSplittedByDateTimeSeparator[0]);
var valueTimeAndValuePart = valueYearPartSplittedByDateTimeSeparator[1];
return string.Concat(normalizedDay, '-', normalizedMonth, '-', normalizedYear, ' ', valueTimeAndValuePart);
}
private static string NormalizeImportDayValue(string value) {
return value.Length == 2 ? value : "0" + value;
}
private static string NormalizeImportMonthValue(string value) {
return value.Length == 2 ? value : "0" + value;
}
private static string NormalizeImportYearValue(string value) {
return value.Length == 4 ? value : DateTime.Now.Year.ToString(CultureInfo.InvariantCulture).Remove(2) + value;
}
Well you can use this one to get the date and the value.
(((0[1-9]|[12][0-9]|3[01])-(0[1-9]|1[012])-(19|20)\d\d)\s((\d{2}:?){3})|(\d+\.?\d+))
This will give you 2 matches
1º 18-06-2014 12:00:00
2º 220.6
Example:
http://regexr.com/391d3
This regex matches both kinds of strings, capturing the two tokens to Groups 1 and 2.
Note that we are not using \d because in .NET it can match any Unicode digits such as Thai...
The key is in the [ |] character class, which specifies your two allowable delimiters
Here is the regex:
^([0-9]{2}-[0-9]{2}-[0-9]{4} (?:[0-9]{2}:){2}[0-9]{2})[ |]([0-9]{3}\.[0-9])$
In the demo, please pay attention to the capture Groups in the right pane.
Here is how to retrieve the values:
var myRegex = new Regex(#"^([0-9]{2}-[0-9]{2}-[0-9]{4} (?:[0-9]{2}:){2}[0-9]{2})[ |]([0-9]{3}\.[0-9])$", RegexOptions.IgnoreCase);
string mydate = myRegex.Match(s1).Groups[1].Value;
Console.WriteLine(mydate);
string myvalue = myRegex.Match(s1).Groups[1].Value;
Console.WriteLine(myvalue);
Please let me know if you have questions
Given the provided format I'd use something like
char delimiter = ' '; //or whatever the delimiter for the specific file is, this can be set in a previous step
int index = line.LastIndexOf(delimiter);
var date = line.Remove(index);
var value = line.Substring(++index);
If there are that many lines and efficiency matters, you could obtain the delimiter once on the first line, by looping back from the end and find the first index that is not a digit or dot (or comma if the value can contain those) to determine the delimiter, and then use something such as the above.
If each line can contain a different delimiter, you could always track back to the first not value char as described above and still maintain adequate performance.
Edit: for completeness sake, to find the delimiter, you could perform the following once per file (provided that the delimiter stays consistent within the file)
char delimiter = '\0';
for (int i = line.Length - 1; i >= 0; i--)
{
var c= line[i];
if (!char.IsDigit(c) && c != '.')
{
delimiter = c;
break;
}
}
I have a list of strings.. each one looks similar to this:
"\n\t\"BLOCK\",\"HEADER-\"\r\n\t\t\"NAME\",\"147430\"\r\n\t\t\"REVISION\",\"0000\"\r\n\t\t\"DATE\",\"11/11/10\"\r\n\t\t\"TIME\",\"10:03:47\"\r\n\t\t\"PMABAR\",\"\"\r\n\t\t\"COMMENT\",\"\"\r\n\t\t\"PTPNAME\",\"0805C\"\r\n\t\t\"CMPNAME\",\"0805C\"\r\n\t\"BLOCK\",\"PRTIDDT-\"\r\n\t\t\"PMAPP\",1\r\n\t\t\"PMADC\",0\r\n\t\t\"ComponentQty\",4\r\n\t\"BLOCK\",\"PRTFORM-\"\r\n\t\t\....(more)...."
What I am trying to do is keep that entire string BUT... replace the DATE, TIME and ComponentQty.....
I want to place the date variable that i have set for the DATE, as well as the DateTime.Now.ToString(""HH:mm:ss") for the TIME ... and a dictionary[part] for the ComponentQty. These values would replace like so:
"DATE","11/11/10" with "DATE","12/06/11"
"TIME","10:03:47" with "TIME","10:30:10"
"ComponentQty",4 with "ComponentQty", 8
or something similar...
so the new string would look like this:
"\n\t\"BLOCK\",\"HEADER-\"\r\n\t\t\"NAME\",\"147430\"\r\n\t\t\"REVISION\",\"0000\"\r\n\t\t\"DATE\",\"12/06/11\"\r\n\t\t\"TIME\",\"10:30:10"\"\r\n\t\t\"PMABAR\",\"\"\r\n\t\t\"COMMENT\",\"\"\r\n\t\t\"PTPNAME\",\"0805C\"\r\n\t\t\"CMPNAME\",\"0805C\"\r\n\t\"BLOCK\",\"PRTIDDT-\"\r\n\t\t\"PMAPP\",1\r\n\t\t\"PMADC\",0\r\n\t\t\"ComponentQty\",8\r\n\t\"BLOCK\",\"PRTFORM-\"\r\n\t\t\....(more)...."
What is the quickest way to do such a thing? I was thinking Regex but I am not too sure on how to go about doing this. Can anyone help?
EDIT:
I used just a normal string replace to do it.. but the replaced data will not always have the statc date, time, compQty that I have below (11/11/10, 10:03:47, 4)... I need to find a way to make that section not hard coded -- with regex I am assuming..
var newDate = "DATE\",\"" + date + "\"";
var newTime = "TIME\",\"" + DateTime.Now.ToString("HH:mm:ss") + "\"";
var newCompQTY = "ComponentQty\"," + dictionary[part];
trimmedDataBasePart = trimmedDataBasePart.ToUpper().Replace("DATE\",\"11/11/10", newDate);
trimmedDataBasePart = trimmedDataBasePart.ToUpper().Replace("TIME\",\"10:03:47", newTime);
trimmedDataBasePart = trimmedDataBasePart.ToUpper().Replace("COMPONENTQTY\",4", newCompQTY);
I am trying to set a value to a Regex and am not sure how to do so... this is what I was trying... but it obviously does not work because the var is not a string. any suggestions?
var newDate = "DATE\",\"" + date + "\"";
var regexedDate = Regex.Match(trimmedDataBasePart, "DATE\",[0-9]+/[0-9]+/[0-9]+");
trimmedDataBasePart = trimmedDataBasePart.ToUpper().Replace(regexedDate, newDate);
Try this:
resultString = Regex.Replace(subjectString, #"(.*\bDATE\b\D*).*?(\\.*\bTIME\b\D*).*?(\\.*\bComponentQty\b\D*)\d+(.*)", "$1NEW_DATE$2NEW_TIME$3NEW_QTY", RegexOptions.Singleline);
Where NEW_DATE should be replaced by your date, NEW_TIME by your time, and NEW_QTY by your new qty.
You can create the replacement string from other variables as you please :)
Well well well, .NET and interpolated variables suck.. If you try to change use "$11" in replacement it thinks it has to use backreference #11 and it fails. Also Regexbuddy had a bug which produced the wrong regex. This is tested and works!
string subjectString = "\n\t\"BLOCK\",\"HEADER-\"\r\n\t\t\"NAME\",\"147430\"\r\n\t\t\"REVISION\",\"0000\"\r\n\t\t\"DATE\",\"11/11/10\"\r\n\t\t\"TIME\",\"10:03:47\"\r\n\t\t\"PMABAR\",\"\"\r\n\t\t\"COMMENT\",\"\"\r\n\t\t\"PTPNAME\",\"0805C\"\r\n\t\t\"CMPNAME\",\"0805C\"\r\n\t\"BLOCK\",\"PRTIDDT-\"\r\n\t\t\"PMAPP\",1\r\n\t\t\"PMADC\",0\r\n\t\t\"ComponentQty\",4\r\n\t\"BLOCK\",\"PRTFORM-\"\r\n\t\t....(more)....";
Regex regexObj = new Regex(#"^(.*\bDATE\b\D*).*?(\"".*?\bTIME\b\D*).*?(\"".*?\bComponentQty\b\D*)\d+(.*)$", RegexOptions.Singleline);
StringBuilder myResult = new StringBuilder();
Match matchResults = regexObj.Match(subjectString);
while (matchResults.Success)
{
for (int i = 1; i < matchResults.Groups.Count; i++)
{
Group groupObj = matchResults.Groups[i];
if (groupObj.Success)
{
myResult.Append(groupObj.Value);
switch (i)
{
case 1:
myResult.Append("NEW_DATE");
break;
case 2:
myResult.Append("NEW_TIME");
break;
case 3:
myResult.Append("NEW QTY");
break;
}
}
}
matchResults = matchResults.NextMatch();
}
Console.WriteLine("Final Result : \n\n\n{0}", myResult.ToString());
Output:
Final Result :
"BLOCK","HEADER-"
"NAME","147430"
"REVISION","0000"
"DATE","NEW_DATE"
"TIME","NEW_TIME"
"PMABAR",""
"COMMENT",""
"PTPNAME","0805C"
"CMPNAME","0805C"
"BLOCK","PRTIDDT-"
"PMAPP",1
"PMADC",0
"ComponentQty",NEW QTY
"BLOCK","PRTFORM-"
....(more)....
By the way you have a falsely escaped dot in your input string. Cheers and have fun! :)
If you can change the way your source string looks, I would use String.Format:
string s = String.Format("Date={0}, Name={1}, Quantity={2}", date, name, quantity);
The placeholders {0}, {1}, {2} are replaced with the specified arguments which follow.
To make it cleaner I would create a function to parse that string list, and then another function to create such a string list instead of using regexps. I think this will make your code easier to maintain.
Dictionary<string, string> Parse(List<string> data)
{
...
}
List<string> CreateStringList(Dictionary<string, string> values)
{
...
}
List<string> SetValues(List<string> data)
{
Dictionary<string, string> values = Parse(data);
values["DATE"] = "12/06/11";
values["TIME"] = "10:30:10";
values["ComponentQty"] = "4";
return CreateStringList(values);
}
I'm doing up an application that converts the STRING duration of a media file in C#.
How do I make it so that the output are as follows:
a. 1:34 (1min 34 sec) to
00:01:34
b. 0:05 (5 seconds) to
00:00:05
c. 1:10:05 to 01:10:05
Result will be displayed in a label named lblDuration.
I am using VS2008 C#.
Thanks if you can help.
I would parse it as a TimeSpan, and then reformat it using
string text = timeSpan.ToString("hh':'mm':'ss");
This is assuming you're using .NET 4 with its support for custom TimeSpan formats. Before .NET 4 you'd have to write it yourself - not too hard, but harder than the above.
Parsing the timespan to start with is a different matter - you could use TimeSpan.TryParseExact passing in multiple formats, for example.
The benefit of parsing and then reformatting is that you'll validate that you've got sensible date - e.g. not "99:99".
Split the string with a colon (':'), convert each element to a number and print each number using %02d, putting a ':' between 1st and 2nd and 2nd and 3rd
I think the nicest thing to do here is use TimeSpan.TryParse, BUT we have to be careful - if that method sees an input string with only one :, it will parse it as hours:minutes!
(TryParseExact gets fiddly because no single format accepts both leading zeroes and the absence of leading zeroes).
So:
var input = "5:06";
TimeSpan ts;
var parseSuccessful = TimeSpan.TryParse(input, out ts);
if (parseSuccessful)
{
if (input.Count(c => c == ':') == 1)
{
// TryParse parsed this as hh:mm but we want it to mean mm:ss
// so scale appropriately
ts = new TimeSpan(ts.Ticks / 60);
}
Console.WriteLine(ts.ToString(#"hh\:mm\:ss"));
}
How about parsing it to a DateTime object then formatting it that way e.g.
DateTime.ParseExact("1:32", 'H:mm', CultureInfo.InvariantCulture).ToString("HH:mm:ss");
Just to clarify - The above solution is a work-around for .NET versions prior to 4 in which you don't have access to custom TimeSpan formats. If you are using .NET 4 then I would definitely recommend using the TimeSpan as #Jon has suggested
private static string GetLable(string text)
{
if (string.IsNullOrEmpty(text))
return "00:00:00";
var builder = new StringBuilder();
var arr = text.Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
if (arr.Length == 2)
builder.Append("00:");
var i = 0;
foreach (var t in arr)
{
builder.Append(t.Length == 1 ? "0" + t : t);
if (arr.Length - 1 != i++)
builder.Append(":");
}
return builder.ToString();
}
public void convertString()
{
string str;
str = "your time";
int length = str.Length;
if (length == 4)
{
str = "00" + ":" +"0"+ str;
}
if (length == 5)
{
str = "00" + ":" + str;
}
}
static void Main(string[] args)
{
Program p = new Program();
p.convertString();
}
How can I remove duplicate substrings within a string? so for instance if I have a string like smith:rodgers:someone:smith:white then how can I get a new string that has the extra smith removed like smith:rodgers:someone:white. Also I'd like to keep the colons even though they are duplicated.
many thanks
string input = "smith:rodgers:someone:smith:white";
string output = string.Join(":", input.Split(':').Distinct().ToArray());
Of course this code assumes that you're only looking for duplicate "field" values. That won't remove "smithsmith" in the following string:
"smith:rodgers:someone:smithsmith:white"
It would be possible to write an algorithm to do that, but quite difficult to make it efficient...
Something like this:
string withoutDuplicates = String.Join(":", myString.Split(':').Distinct().ToArray());
Assuming the format of that string:
var theString = "smith:rodgers:someone:smith:white";
var subStrings = theString.Split(new char[] { ':' });
var uniqueEntries = new List<string>();
foreach(var item in subStrings)
{
if (!uniqueEntries.Contains(item))
{
uniqueEntries.Add(item);
}
}
var uniquifiedStringBuilder = new StringBuilder();
foreach(var item in uniqueEntries)
{
uniquifiedStringBuilder.AppendFormat("{0}:", item);
}
var uniqueString = uniquifiedStringBuilder.ToString().Substring(0, uniquifiedStringBuilder.Length - 1);
Is rather long-winded but shows the process to get from one to the other.
not sure why you want to keep the duplicate colons. if you are expecting the output to be "smith:rodgers:someone::white" try this code:
public static string RemoveDuplicates(string input)
{
string output = string.Empty;
System.Collections.Specialized.StringCollection unique = new System.Collections.Specialized.StringCollection();
string[] parts = input.Split(':');
foreach (string part in parts)
{
output += ":";
if (!unique.Contains(part))
{
unique.Add(part);
output += part;
}
}
output = output.Substring(1);
return output;
}
ofcourse i've not checked for null input, but i'm sure u'll do it ;)