Varying filepaths in C# - c#

I am creating C# Windows Form that retrieves files from shared drives as email attachments. I am trying to automate the file retrieval process, but the filepaths available to me vary according to the date. For example:
V:\....\Dec-03\filename12-3-2013.xml
J:\.....\December\filename12-4-2013
I have the filepath stored as string from a textbox, but since the path varies slightly day-to-day, I've been trying to figure out how automate this process. In the past I've used VBA code where I've concatenated method calls into the string like this
"..." & Day(Date) & "..."
(I replaced the ampersand with the plus sign of course for C#)
But this just gets me an illegal characters in path Argument exception.
I am using a check for filedate and taking a a specific filepath through a textbox. I want particular files that are being updated in monthly folders and the filename contains a date. I want to grab the ones with today's date or yesterday's date, but some have no date in the filename or directory at all. Since there isn't a lot of consistency, I would love to enter code
"+ DateTime.Now.ToString() +"
in the textbox per individual filepath as I load them via the form and have the program execute like I've done with some VBA code, but I get Illegal characters with the double quotes in the middle of a filepath. Is there some work around or will I need to create fixes for every particular pattern?

Use System.IO.Path.Combine(...) to handle chaining directories together (it takes care of extra slashes for you). In your combine, use String.Format(SomeFormatString, token1value, toke2value, etc.) to give you the name you were wanting.
C# uses + to append strings instead of & in older VB.
"My Date: " + DateTime.Now.ToString("MM/dd/yyyy")
An example of this with the String.Format I showed above would be
string.Format("My Date: {0}", DateTime.Now.ToString("MM/dd/yyyy"))

If I'm following what you're saying about Day(Date), you might try some thing like this in C#:
MyObject.SomeMethod("some string " + dateValue.ToString("ddd") + " more string data");
Where dateValue is a DateTime object and the "ddd" parameter tells the ToString method to return a three character abbreviation of the day of the week (e.g. 'Wed').
For more information on using ToString with DateTime objects to extract various parts of the date, see
http://msdn.microsoft.com/en-us/library/bb762911(v=vs.100).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-2

The ToString overload of the DateTime structure will allow you to format a date as the Month name, etc.
var x = DateTime.Today.ToString("MMMM"); // December
You can include other characters in the format string as well, for example to get Dec-19 you can use:
var x = DateTime.Today.ToString("MMM-dd"); // Dec-19
TyCobb's answer covers combining the formatted date into a path using Path.Combine (which I generally recommend).
You can also use String.Format to insert a formatted value into a string, which is often easier to read and leads to fewer mistakes. For example, to generate your first example, you could use the following:
var path =
String.Format("V:....\{0:MMM-dd}\filename{0:M-d-yyyy}.xml", DateTime.Today);

Related

Delete character out of string

I am having some problems with a quite easy task - i feel like im missing something very obvious here.
I have a .csv file which is semicolon seperated. In this file are several numbers that contain dots like "1.300" but there are also dates included like "2015.12.01". The task is to find and delete all dots but only those that are in numbers and not in dates. The dates and numbers are completely variable and never at the same position in the file.
My question now: What is the 'best' way to handle this problem?
From a programmers point of view: Is it a good solution to just split at every semilicon, count the dots and if there is only one dot, delete it? This is the only way to solve the problem i could think of by now.
Example source file:
2015.12.01;
13.100;
500;
1.200;
100;
Example result:
2015.12.01;
13100;
500;
1200;
100;
If you can rely on the fact that dates have two dots and numbers just one, you can use that as a filter:
string s = "123.45";
if (s.Count(x => x == '.') == 1)
{
s = s.Replace(".", null);
}
The source file looks like a valid file generated by a program running on a machine whose locale uses . as the thousand separator (most of Europe does) and date separator (German locales only I think). Such locales also use ; as the list separator.
If the question was only how to parse such dates, numbers, the answer would be to pass the proper culture to the parse function, eg: decimal.Parse("13.500",new CultureInfo("de-at")) would return 13500. The actual issue though is that the data must be fed to another program that uses . as the decimal separator.
The safest option would be to change the locale used by the exporting program, eg change the thread CultureInfo if the exporter is a .NET program, the locale in an SSIS package etc, to a locale like en-gb to export with . and avoid the weird date format. This assumes that the next program in the pipeline doesn't use German for the date, English for numbers
Another option would be to load the text, parse the fields using the proper locale then export them in the format required by the next program.
Finally, a regular expression could be used to match only the numeric fields and remove the dot. This can be a bit tricky and depends on the actual contents.
For example (\d+)\.(\d{3}) can be used to match numbers if there is only one thousand separator. This can fail if some text field contains similar values. Or ;(\d+)\.(\d{3}); could match only a full field, except the first and last fields, eg:
Regex.Replace("1.457;2016.12.30;13.000;1,50;2015.12.04;13.456",#";(\d+)\.(\d{3});",#"$1$2;")
produces :
1.457;2016.12.3013000;1,50;2015.12.04;13.456
A regular expression that would match either numbers between ; or the first/last field could be
(^|;)(\d+)\.(\d{3})(;|$)
This would produce 1457;2016.12.30;13000;1,50;2015.12.04;13456, eg:
var data="1.457;2016.12.30;13.000;1,50;2015.12.04;13.456";
var pattern=#"(^|;)(\d+)\.(\d{3})(;|$)";
var replacement=#"$1$2$3$4";
var result= Regex.Replace(data,pattern,replacement);
The advantage of a regex over splitting and replacing strings is that it's a lot faster and more memory efficient. Instead of generating temporary strings for each split, manipulation, a Regex only calculates indexes in the source. A string object is generated only when you request the final text result. This results in far fewer allocations and garbage collections.
Even in medium-sized files this can result in 10x better performance
I wouldn't rely on the number of dots as mistakes can be made.
You can use the double.TryParse to safely test if the string is a number
var data = "2015.12.01;13.100;500;1.200;100;";
var dataArray = data.Split(';');
foreach (var s in dataArray)
{
double result;
if(double.TryParse(s,out result))
// implement your logic here
Console.WriteLine(s.Replace(".",string.Empty));
}

string format custom parameter

Is there a (simple/predefined) way to use the same string.format mechanism but use names instead of numbers? I want to use the same formatting system but make it more end-user friendly. Right now my users are putting in {0} {1:Minutes} after selecting what parameters they want to use from a list but it becomes quite unreadable and confusing once you start using more then say 2 parameters.
For example want to do {Now} and {Now:Minutes} and have it replaced with DateTime.Now for {Now} and DateTime.Now.Minutes using the IFormattable for {Now:Minutes}. So that the users won't need to select items from a list anymore but rather just type/insert the names of the parameters.
In c#-6.0 you can use
string result = $"Time: {DateTime.Now}";
On previous versions see
How to replace tokens on a string template?

How to include Variables in Localized Strings?

I'm trying to display a message to the user along the lines of:
"User 5 could not be added"
But how can I add variables to a string that is being placed in a .resx file? I've trying searching for things like "Variables in Localization" "Globalization with Variables" etc, but came up dry.
If I weren't localizing I would write:
Console.Write("User " + userNum + " could not be added");
How can this be accomplished with resources?
You can't do this directly.
What you can do is place a token - a specific string that can be replaced with string.Replace with the value of the variable.
A good candidate for this would be the built in string formatting:
Console.Write(string.Format("User {0} could not be added", userNum));
Assuming userNum has the value 5, the result would be:
User 5 could not be added
You can localize this string with the composite format specifiers.
In teams where I've done internationalization, we generally also created a resource for the format string, something like USER_COULD_NOT_BE_ADDED_FORMAT, and called String.Format (or your environment's equivalent) by passing that resource's value as the format pattern.
Then you'll do Console.Write(String.Format(resourceManager.GetString("USER_COULD_NOT_BE_ADDED_FORMAT"), userNum));
Most localizers either have training in the format strings used by the system they are localizing, or they are provided with guidance in the localization kit that you provide them. So this is not, for example, as high a barrier as making them modify code directly.
You generally need to add a loc comment to the resource ID to explain the positional parameters.
Use Composite Formatting like so:
Console.Write("User {0} could not be added", userNum);
This way you would localize "User {0} could not be added".
you can do that its simple
new lets see how
String.Format(Resource_en.PhoneNumberForEmployeeAlreadyExist,letterForm.EmployeeName[i])
this will gave me dynamic message every time
by the way I'm useing ResXManager
I would use string.Format
http://msdn.microsoft.com/en-us/library/system.string.format.aspx
Console.Write(string.Format("User {0} could not be added", userNum));

Removing data from returned information.

I am making an SQL Query that brings back a list of files and their paths. They have different file paths and different file names ofc.
The file names are dates and time in the following format:
YearMonthDayHourMinuteSeconds
What I need to do is take the filepath that has the latest date and time, strip off everything except the date and time part and then using the date and time re-query the database.
I have very few ideas on how to do this.
EDIT: The date will be changing and I need to take the latest when ever the program is run.
My first idea would be to treat everything the query returns as strings
When you get your result set, you could iterate through it storing the record you want in a string or multiple strings. You can compare strings with firststring.Compare(secondstring) it returns 1 or greater if the secondstring is alfabeticaly after firststring.
Then use substring to extract the part of the string you want
string inf = latestdate.Substring(startindex, length);
Hope this helps
use the standard .NET file operation libraries
something like:
using System.IO;
...
string myFileNameWithFullPath;
...
DateTime newDate = DateTime.Parse(Path.GetFileName(myFileNameWithFullPath));
string tmps = Path.GetFileNameWithoutExtension(filenameFromSQL);
DateTime myDateTime = DateTime.Parse(String.Format("{1}/{2}/{0}",
tmps.Substring(0,4), tmps.Substring(5,2), tmps.Substring(7,2));

C#: How do you go upon constructing a multi-lined string during design time?

How would I accomplish displaying a line as the one below in a console window by writing it into a variable during design time then just calling Console.WriteLine(sDescription) to display it?
Options:
-t Description of -t argument.
-b Description of -b argument.
If I understand your question right, what you need is the # sign in front of your string. This will make the compiler take in your string literally (including newlines etc)
In your case I would write the following:
String sDescription =
#"Options:
-t Description of -t argument.";
So far for your question (I hope), but I would suggest to just use several WriteLines.
The performance loss is next to nothing and it just is more adaptable.
You could work with a format string so you would go for this:
string formatString = "{0:10} {1}";
Console.WriteLine("Options:");
Console.WriteLine(formatString, "-t", "Description of -t argument.");
Console.WriteLine(formatString, "-b", "Description of -b argument.");
the formatstring makes sure your lines are formatted nicely without putting spaces manually and makes sure that if you ever want to make the format different you just need to do it in one place.
Console.Write("Options:\n\tSomething\t\tElse");
produces
Options:
Something Else
\n for next line, \t for tab, for more professional layouts try the field-width setting with format specifiers.
http://msdn.microsoft.com/en-us/library/txafckwd.aspx
If this is a /? screen, I tend to throw the text into a .txt file that I embed via a resx file. Then I just edit the txt file. This then gets exposed as a string property on the generated resx class.
If needed, I embed standard string.Format symbols into my txt for replacement.
Personally I'd normally just write three Console.WriteLine calls. I know that gives extra fluff, but it lines the text up appropriately and it guarantees that it'll use the right line terminator for whatever platform I'm running on. An alternative would be to use a verbatim string literal, but that will "fix" the line terminator at compile-time.
I know C# is mostly used on windows machines, but please, please, please try to write your code as platform neutral. Not all platforms have the same end of line character. To properly retrieve the end of line character for the currently executing platform you should use:
System.Environment.NewLine
Maybe I'm just anal because I am a former java programmer who ran apps on many platforms, but you never know what the platform of the future is.
The "best" answer depends on where the information you're displaying comes from.
If you want to hard code it, using an "#" string is very effective, though you'll find that getting it to display right plays merry hell with your code formatting.
For a more substantial piece of text (more than a couple of lines), embedding a text resources is good.
But, if you need to construct the string on the fly, say by looping over the commandline parameters supported by your application, then you should investigate both StringBuilder and Format Strings.
StringBuilder has methods like AppendFormat() that accept format strings, making it easy to build up lines of format.
Format Strings make it easy to combine multiple items together. Note that Format strings may be used to format things to a specific width.
To quote the MSDN page linked above:
Format Item Syntax
Each format item takes the following
form and consists of the following
components:
{index[,alignment][:formatString]}
The matching braces ("{" and "}") are
required.
Index Component
The mandatory index component, also
called a parameter specifier, is a
number starting from 0 that identifies
a corresponding item in the list of
objects ...
Alignment Component
The optional alignment component is a
signed integer indicating the
preferred formatted field width. If
the value of alignment is less than
the length of the formatted string,
alignment is ignored and the length of
the formatted string is used as the
field width. The formatted data in
the field is right-aligned if
alignment is positive and left-aligned
if alignment is negative. If padding
is necessary, white space is used. The
comma is required if alignment is
specified.
Format String Component
The optional formatString component is
a format string that is appropriate
for the type of object being formatted
...

Categories