Display Format String to User - c#

How do I go about displaying a format string as-is?
I have a property decorated with some data annotations:
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")]
public blah blah { get; set; }
I now have a reference to the format string:
string format = metadata.DisplayFormatString; // == {0:MM/dd/yyyy}
I want to display this format string to the user without manually typing it in my view. Is there a nice way (not replace chars with empty string) to get MM/dd/yyyy from the string format?

I thing using replace is a nice way too. If you're concerned about clutter in the view, you could put this into an extension method (or even an HTML Helper extension method).
public static string ToUserFriendlyDateFormat(this string unfriendlyFormat) {
return unfriendlyFormat
.Replace("{0:", string.Empty)
.Replace("}", string.Empty);
}

I don't know what all your format strings look like, but if your format strings ever make it to String.Format() you already have to escape { and } characters (by doubling them). How about using a regular expression. Here's something simple to start with that will also undouble the { and } characters:
string DisplayFormat(string format) {
Regex rx = new Regex(#"\{\d+:([^}]+)}|\{\{|}}");
return rx.Replace(format, delegate(Match m) {
if (m.Value == "{{") {
return "{";
} else if (m.Value == "}}") {
return "}";
} else {
return m.Groups[1].Value;
}
});
}
Note that the above code will have to change if your format strings contain sequences like {0} and you want something special done with them as well.

Related

Format a string in C# (not number or date) to a given pattern

Is there something like string.format for formatting strings where I can pass a the goal pattern. string.format seems to be only for formatting numbers and patterns and inserting values inside a given position. Is there a general solution to formatting strings after a given pattern than programming it out myself?
I want to give the goal pattern and an input string and get out the string in the pattern I’ve provided.
I can give some examples.
Input Output Input pattern (idea)
---------------------------------------------------------
123.456.001 00123.456.001 00000.000.###
D1234567 D-123-4567 D-000-#### (where D is literal)
So, my question is: Is there a way to format a string to a given pattern like there is for number and dates?
I would consider making customer formatter classes for each of the different formats you require. There is a very simple example below with no error handling etc...
// custom formatter class
public class FormatD : IFormattable
{
public string ToString(string format, IFormatProvider provider)
{
return format[0] + "-" + format.Substring(1,3) + "-" + format.Substring(4);
}
}
To call:
var input = "D1234567";
var ouput = String.Format("{0:" + input + "}", new FormatD());
This is not really possible with String.Format(). You would need to dissect the different parts of your pattern using regular expressions or similar.
For your example a solution could be
public string ReplacePattern(string input)
{
var match = Regex.Match(input, #"([A-Z])(\d{3})(\d{4})");
if(match.Groups.Count == 4) // The first group is always the input
{
return String.Format("{0}-{1}-{2}", match.Groups.Skip(1).Take(3).ToArray());
}
return "";
}
Edit: I forgot: of course you can always use regular expression replacements:
public string ReplacePattern(string input)
{
return Regex.Replace(input, #"([A-Z])(\d{3})(\d{4})", "$1-$2-$3");
}

How can the parameter for string.format cut the string

I need to make a possibility to open a webpage either with an additional parameter or without one. If it has a parameter, I'll add it with the string.format function. Sometimes I need to format this parameter before opening the url, however, I don't want to make the code too specific.
The Parameter is always a string and I would need to cut the end of this string. Is it possible to do something in the string to be formatted to cut the unneeded text? If so how would the {0} have to look that it works?
string url = "http://foo.bar/xt:{0}";
string parameter = "abcdefghi";
if (Regex.Matches(Regex.Replace(url,
#"(\{{2}|\}{2})", ""), // removes escaped curly brackets
#"\{(\d+)(?:\:?[^}]*)\}")
.OfType<Match>().Any())
{
Process.Start(string.Format(url, parameter));
}
else
{
Process.Start(url);
}
Instead of abcdefghi I would like to have as parameter just abcdefg for instance. But this should be configurable via url. Something like {0:7) or so...
You have to write this kind of logic yourself. What you can do, however, is wrap this in an extension method so you don't have to duplicate it everywhere:
public static class StringExt
{
public static string Truncate(this string value, int maxLength)
{
if (string.IsNullOrEmpty(value)) return value;
return value.Length <= maxLength ? value : value.Substring(0, maxLength);
}
}
Now we can write:
var someString = "...";
someString = someString.Truncate(2);

DateTime format string for invalid Format string

I am trying to format Datetime string using
date.ToString(format)
If user feeds in wrong format, e.g. "YYYY MM DDr" I would like to know whether I can convert datetime using that format, rather than returning
2015 04 DDr
since
DateTime.ToString(format)
always returns a valid String.
For example, is there any method that perhaps throw an exception on failed conversion so that I can catch and decide not display my output string instead of displaying something like
2015 04 DDr
If you assume that all the letters inserted in your format are either separators or letters that should be converted to a DatePart, you can check if after converting the date you still have non separator chars that were not converted, as follows:
public static class DateTimeExtension
{
public static string ToStringExt(this DateTime p_Date, String format)
{
char[] separators = { ' ', '/', '-' };
String stringDate = p_Date.ToString(format);
foreach (char dateChar in format)
{
if (stringDate.Contains(dateChar) && !separators.Contains(dateChar))
{
throw new FormatException("Format Error");
}
}
return stringDate;
}
}
Edited after #Vladimir Mezentsev observation:
This code assumes that you are converting only to Numbers, if you are doing something that will convert to Day strings like Tuesday, the logic may fail. To address this scenario the code would get a little more complicated but can also be achieved with something like this:
public static string ToStringExt(this DateTime p_Date, String format)
{
foreach (string dateFormatPart in getFormatStrings(format))
{
if (p_Date.ToString(dateFormatPart) == dateFormatPart)
{
throw new FormatException("Format Error");
}
}
return p_Date.ToString(format);
}
private static IEnumerable<string> getFormatStrings(String format)
{
char[] separators = { ' ', '/', '-' };
StringBuilder builder = new StringBuilder();
char previous = format[0];
foreach (char c in format)
{
if (separators.Contains(c) || c != previous)
{
string formatPart = builder.ToString();
if (!String.IsNullOrEmpty(formatPart))
{
yield return formatPart;
builder.Clear();
}
}
if(!separators.Contains(c))
{
builder.Append(c);
}
previous = c;
}
if (builder.Length > 0)
yield return builder.ToString();
}
Have a look at https://msdn.microsoft.com/en-us/library/8kb3ddd4(v=vs.110).aspx. Particularly this part...
If you're wanting to validate the string used to format the DateTime object, then you'll probably have to write your own using the link provided to know what formats are acceptable, and treat any other characters as errors.
There is no invalid format, because you can parse formatted string with exact same format. Even if after parsing you have not loss in any part of date, that could not form the final decision - valid or invalid format.
You should carefully consider what can be appropriate for user, even give him an opportunity to construct format from some predefined blocks. Maybe show sample conversion with confirmation.
For specific formats you can create some extension method where you can apply your business rules and throw exceptions when you need it.

Round-trip-safe escaping of strings in C#

I am confused by all the different escaping mechanisms for strings in C#. What I want is an escaping/unescaping method that:
1) Can be used on any string
2) escape+unescape is guaranteed to return the initial string
3) Replaces all punctuation with something else. If that is too much to ask, then at least commas, braces, and #. I am fine with spaces not being escaped.
4) Is unlikely to ever change.
Does it exist?
EDIT: This is for purposes of seriliazing and deserializing app-generated attributes. So my object may or may not have values for Attribute1, Attribute2, Attribute3, etc. Simplifying a bit, the idea is to do something like the below. Goal is to have the encoded collection be brief and more-or-less human-readable.
I am asking what methods would make sense to use for Escape and Unescape.
public abstract class GenericAttribute {
const string key1 = "KEY1"; //It is fine to put some restrictions on the keys, i.e. no punctuation
const string key2 = "KEY2";
public abstract string Encode(); // NO RESTRICTIONS ON WHAT ENCODE MIGHT RETURN
public static GenericAttribute FromKeyValuePair (string key, string value) {
switch (key) {
case key1: return new ConcreteAttribute1(value);
case key2: return new ConcreteAttribute2(value);
// etc.
}
}
}
public class AttributeCollection {
Dictionary <string, GenericAttribute> Content {get;set;}
public string Encode() {
string r = "";
bool first = true;
foreach (KeyValuePair<string, GenericAttribute> pair in this.Content) {
if (first) {
first = false;
} else {
r+=",";
}
r+=(pair.Key + "=" + Escape(pair.Value.Encode()));
}
return r;
}
public AttributeCollection(string encodedCollection) {
// input string is the return value of the Encode method
this.Content = new Dictionary<string, GenericAttribute>();
string[] array = encodedCollection.Split(',');
foreach(string component in array) {
int equalsIndex = component.IndexOf('=');
string key = component.Substring(0, equalsIndex);
string value = component.Substring(equalsIndex+1);
GenericAttribute attribute = GenericAttribute.FromKeyValuePair(key, Unescape(value));
this.Content[key]=attribute;
}
}
}
I'm not entirely sure what your asking, but I believe your intent is for the escaped character to be included, even with the escape.
var content = #"\'Hello";
Console.WriteLine(content);
// Output:
\'Hello
By utilizing the # it will include said escaping, making it apart of your string. That is for the server-side with C#, to account for other languages and escape formats only you would know that.
You can find some great information on C# escaping here:
MSDN Blog
Try using HttpServerUtility.UrlEncode and HttpServerUtility.UrlDecode. I think that will encode and decode all the things you want.
See the MSDN Docs and here is a description of the mapping on Wikipedia.

What's the most efficient way to pull culture information out of a resx's filename in c#?

What's the most efficient way to pull culture information out of a resx's filename using C#? The solution should also handle there not being culture info in the file name (ie form1.resx). In that case a string assigned "Default" should be returned.
This seems like it would work:
string GetCulture(string s)
{
var arr=s.Split(".");
if(arr.Length>2)
return arr[1];
else
return "Default";
}
Your best bet is just using regex:
string ParseCulture(string input)
{
var r = Regex.new('[\w\d]+\.([\w\-]+)\.resx')
// Match the regular expression pattern against a text string.
Match m = r.Match(input);
if (m.Success)
{
return m.Groups[1];
}
else
{
return "Default";
}
}
This gets back a match (with the phrase you're looking for as the match), or no match (which means you should use "Default").

Categories