How can I achieve formatting string to custom format:
int value = 5000;
String.Format("{0:## ###}", value);
value.ToString("##");
but with value as string, without using conversion to number?
something like this:
String.Format("{0:## ###}, "5000");
** UPDATE:
I'm trying to create a generic function:
public string FormatString(string value, string format = "") {
if (value == null){
return "";
}
return String.Format("{0:" + format + "}", value);
}
public bool OtherFunction(id){
var data = dc.GetData(id);
ViewBag.DescriptionText = FormatString(data.Description).Replace("\n", "<br />");
ViewBag.Phone = FormatString(data.Phone, "(##) ####-#####");
ViewBag.City= FormatString(data.City);
[...]
}
I don't think something like this exists. Like Jon said, this was design for numbers.
If you want just "format" with # you could write simple function, something like this
public string FormatString(string value, string format = "")
{
if (String.IsNullOrEmpty(value) || String.IsNullOrEmpty(format))
return value;
var newValue = new StringBuilder(format);
for (int i = 0; i < newValue.Length; i++)
{
if (newValue[i] == '#')
if (value.Length > 0)
{
newValue[i] = value[0];
value = value.Substring(1);
}
else
{
newValue[i] = '0';
}
}
return newValue.ToString();
}
Of course this is very simple one. You will have to check and decide what to do if format is too long (like here: fill with '0') and when he format is too short (here: just 'truncate' rest of value).
But I think you have an idea how to do this.
Somewhere on my disk I have code for something like this: formatting number in special ways/pattern for invoice number. If I will find this, I'll make some post on blog and paste the link
"5000" is a string. The only overload available for string.ToString() is the one with an IFormatProvider [1]. While you could actually implement that, you'll probably end up in something similar to int.Parse() which you don't like.
[1] http://msdn.microsoft.com/de-de/library/29dxe1x2(v=vs.110).aspx
Related
Edit:
Because of your responses I think I've asked the question wrong.
It's not that my solution doesn't work or isn't very clean. I'm interested if there is a general way, how you can foramt a string. Like you can do it with a int or other data types.
So I couldn't find one. But I hope there is one.
So that's the question I wanted to ask:
Does C# provides a way to format strings, like it does for a int or other data types?
I'm looking for something like this:
myString.Format(myFormat);
or:
myFormattedString = String.Format(myString, myFormat);
And if the answer is no, it's also ok. I just want to know it. (And maybe someone else as well)
Original question:
What's the best way to change the format of a string?
So I have a string that looks like this:
"123456789012345678"
And now I want that:
"12.34.567890.12345678"
I'm using this, but I don't find it very clean:
private string FormatString(string myString)
{
return myString.Insert(2, ".").Insert(5, ".").Insert(12, ".");
}
Things I've tried:
// Too long.
private string FormatString(string myString)
{
return myString.Substring(0, 2)
+ "."
+ myString.Substring(2, 2)
+ "."
+ myString.Substring(4, 6)
+ "."
+ myString.Substring(10, 8);
}
// Convertion from string -> long -> string.
private string FormatString(string myString)
{
return String.Format("{0:##'.'##'.'######'.'########}", long.Parse(myString));
}
I'm looking for something like that:
private string FormatString(string myString)
{
return String.Format("{0:##'.'##'.'######'.'########}", myString);
}
I don't see anything wrong with your code, but if you want a better matching system, you might want to consider regular expressions:
(\d{2})(\d{2})(\d{6})(\d{8})
And replace it with:
$1\.$2\.$3\.$4
(In action)
But my two cents: keep it like it is.
Well...when the framework does not provide what you want, you can always do it yourself.
I've made this method as a experiment. It can surely be optimized and is not fully tested, but it can give you a view of what you could do:
private string FormatString(string myString,string format)
{
const char number = '#';
const char character = '%';
StringBuilder sb = new StringBuilder();
if (format.Length < myString.Length) throw new Exception("Invalid format string");
int i = 0;
foreach (char c in format)
{
switch (c)
{
case number:
if (char.IsDigit(myString[i]))
{
sb.Append(myString[i]);
i++;
}
else
{
throw new Exception("Format string doesn't match input string");
}
break;
case character:
if (!char.IsDigit(myString[i]))
{
sb.Append(myString[i]);
i++;
}
else
{
throw new Exception("Format string doesn't match input string");
}
break;
default:
sb.Append(c);
break;
}
}
return sb.ToString();
}
This method expects the format string to have either a # to denote digit, a % to denote a character, or any other character that would be copied literally to the formatted string.
Usage:
string test = FormatString("123456789012345678", "##.##.######.########");
//outputs 12.34.567890.12345678
string test = FormatString("12345F789012345678", "##.##.#%####.########");
//outputs 12.34.5F7890.12345678
If your string will always be a number then you can do it like this:
string stringData = "123456789012345678";
string dataInFormat = Convert.ToInt64(stringData).ToString(#"##\.##\.######\.########");
First convert string to long and then implement the format on that. In your case it would be like this:
private string FormatString(string myString)
{
return Convert.ToInt64(myString).ToString(#"##\.##\.######\.########");
}
I'm trying to convert an classical integer value like:
2000
into a format like this:
2.000,00
I have tried the following methods:
String.valueOf(input.format());
And this method:
private String getCents(Decimal x){
String y = String.valueOf(x);
String z = '.';
if(y.contains(',')) z = ',';
y = y.substring(0, y.indexOf(z));
if(x - Decimal.valueOf(y) == 0)
return String.valueOf(x.format()) + z + '00';
else return String.valueOf(x.format());
}
But the string class doesn't contains the valueOf method for some reason. Is there any other way to do this ?
The class String does not contain the method valueOf, because this ain't Java, you know.
The method you are searching for is ToString, which allows a format-provider as an argument. The simplest way is another string which defines the format.
int i = 2000;
Console.WriteLine(i.ToString("#,##0.00"));
Console.ReadLine();
This will do what you want to do.
Read more about format-providers in the docs of the ToStringmethod.
given en-US culture
this will do:
string.Format(CultureInfo.GetCultureInfo("en-US"), "{0:N}", 2000)
So I'm trying to read from a text file and store each field into an array. But when I tried to convert accountNumber to an Int, I get an error.
public bool matchCustomer(int accountID){
string[] data = null;
string line = Global.currentFile.reader.ReadLine();
while (line != null)
{
data = line.Split('*');
this.accountNumber = Convert.ToInt32(data[0]);
line = Global.currentFile.reader.ReadLine();
if (accountID == this.accountNumber)
{
return true;
}
}
return false;
}
That's because data[0] isn't convertible into an int. What is data[0] at runtime?
You could use:
int value;
if(Int32.TryParse(data[0], out value))
{
accountNumber = value;
}
else
{
//Something when data[0] can't be turned into an int.
//You'll have to decide this logic.
}
Likely, because you split by delimiter * in the string:
12345 * Shrek * 1209 * 100,000 * 50,000
You left with a spaced number "12345 " instead of all numbers "12345". This causes it to be unconvertible. Try to apply Trim:
this.accountNumber = Convert.ToInt32(data[0].Trim());
Also, beware of strings with thousands separator comma (50,000 and 100,000). You might need to replace it with empty string if it is unconvertible:
data[4].Replace(",","").Trim();
Other two answers addressed the issue and fix, I thought of providing another alternative which uses Linq.
You can replace complete while block content with this.
return line.Split('*').Select(s=> s.Trim().Replace(",", ""))
.Where(c=> Regex.IsMatch(c.Trim(), #"\d+"))
.Select(s=>int.Parse(s.Trim()))
.Any(e=>e == accountId);
Working Demo
I'd need to get a html friendly version of a truncated Xhtmlstring as the tag endings might get clipped when truncated. Any ideas on how to achieve this? I've thought of just getting rid of all tags first and then clipping but is there a solution for this inside episerver or is this just basic string-manipulation with regex?
There is a built-in helper function in the TextIndexer class called StripHtml which can be used to remove any tags to end up with plain text before truncating:
var plainText = TextIndexer.StripHtml(someHtml);
Note that this method can also be used to truncate the string like so:
// Truncate to 150 characters
var truncatedString = TextIndexer.StripHtml(someHtml, 150);
You'll also be able to have a string such as "..." appended to the string if it was truncated.
For valid XHTML you can use the XElement class to simplify things, i.e. you do not care for the occasional regular expression frenzy. The following example should work well for the trivial case when there is only one text-node present:
public class Truncator {
private const String Ellipsis = "…";
private const String EllipsisHtmlEntity = "…";
public static String Truncate(XElement xElement, Int32 length, Boolean useHtmlEntity = false) {
if (ReferenceEquals(xElement, null))
throw new ArgumentException(nameof(xElement));
var textNode =
(XText)
xElement.DescendantNodes()
.FirstOrDefault(node => !ReferenceEquals(node, null) && node.NodeType == XmlNodeType.Text);
if (!ReferenceEquals(textNode, null))
textNode.Value = Truncate(textNode.Value, length);
var truncatedResult = xElement.ToString(SaveOptions.DisableFormatting);
return useHtmlEntity ? truncatedResult.Replace(Ellipsis, EllipsisHtmlEntity) : truncatedResult;
}
public static String Truncate(String str, Int32 length, Boolean useHtmlEntity = false) {
if (String.IsNullOrWhiteSpace(str))
return str;
var truncated = str.Trim().Substring(0, length - 1).Trim();
return String.IsNullOrWhiteSpace(str) || str.Length < length
? str
: $"{truncated}{(useHtmlEntity ? EllipsisHtmlEntity : Ellipsis)}";
}
}
If you have a String to begin with, just XElement.Parse(it) to get the XElement.
I have a string like "1.5%" and want to convert it to double value.
It can be done simple with following:
public static double FromPercentageString(this string value)
{
return double.Parse(value.SubString(0, value.Length - 1)) / 100;
}
but I don't want to use this parsing approach.
Is any other approach with IFormatProvider or something like this?
It is culture sensitive, replace it like this:
value = value.Replace(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PercentSymbol, "");
Then parse it.
If you care about catching formatting errors, I would use TrimEnd rather than Replace. Replace would allow formatting errors to pass undetected.
var num = decimal.Parse( value.TrimEnd( new char[] { '%', ' ' } ) ) / 100M;
This will ensure that the value must be some decimal number followed by any number of spaces and percent signs, i.e, it must at least start with a value in the proper format. To be more precise you might want to split on '%', not removing empty entries, then make sure that there are only two results and the second is empty. The first should be the value to convert.
var pieces = value.Split( '%' );
if (pieces.Length > 2 || !string.IsNullOrEmpty(pieces[1]))
{
... some error handling ...
}
var num = decimal.Parse( pieces[0] ) / 100M;
Using Replace will allow you to successfully, and wrongfully IMO, parse things like:
%1.5
1%.5
1.%5
in addtion to 1.5%
Only slightly better, but less error-prone:
public static double FromPercentageString(this string value)
{
return double.Parse(value.Replace("%","")) / 100;
}
TypeConverter provides a unified way of converting types of values to other types, as well as for accessing standard values and subproperties. http://msdn.microsoft.com/en-us/library/system.componentmodel.typeconverter%28VS.80%29.aspx
This is probably overkill for one-off conversions. It is far more useful when binding properties in ASP.NET or XAML, or when parsing config files.
var result = new Percentage("1.5%");
double d = result.Value;
Percentage and its TypeConverter are defined as:
[TypeConverter(typeof(PercentageConverter))]
public struct Percentage
{
public double Value;
public Percentage( double value )
{
Value = value;
}
public Percentage( string value )
{
var pct = (Percentage) TypeDescriptor.GetConverter(GetType()).ConvertFromString(value);
Value = pct.Value;
}
public override string ToString()
{
return ToString(CultureInfo.InvariantCulture);
}
public string ToString(CultureInfo Culture)
{
return TypeDescriptor.GetConverter(GetType()).ConvertToString(null, Culture, this);
}
}
public class PercentageConverter : TypeConverter
{
static TypeConverter conv = TypeDescriptor.GetConverter(typeof(double));
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return conv.CanConvertFrom(context, sourceType);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(Percentage)) {
return true;
}
return conv.CanConvertTo(context, destinationType);
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value == null) {
return new Percentage();
}
if (value is string) {
string s = value as string;
s = s.TrimEnd(' ', '\t', '\r', '\n');
var percentage = s.EndsWith(culture.NumberFormat.PercentSymbol);
if (percentage) {
s = s.Substring(0, s.Length - culture.NumberFormat.PercentSymbol.Length);
}
double result = (double) conv.ConvertFromString(s);
if (percentage) {
result /= 100;
}
return new Percentage(result);
}
return new Percentage( (double) conv.ConvertFrom( context, culture, value ));
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (!(value is Percentage)) {
throw new ArgumentNullException("value");
}
var pct = (Percentage) value;
if (destinationType == typeof(string)) {
return conv.ConvertTo( context, culture, pct.Value * 100, destinationType ) + culture.NumberFormat.PercentSymbol;
}
return conv.ConvertTo( context, culture, pct.Value, destinationType );
}
}
It seems that many answers to this question involve replacing the culture's percentage symbol with the empty string, and then parsing the resulting string as a numeric value.
Perhaps I'm missing something, but there are still some unhandled cases here. Specifically, what happens if the PercentDecimalSeparator is different to the NumberDecimalSeparator for the current culture? What happens if the PercentGroupSeparator is different to the NumberGroupSeparator for the current culture? What happens if the PercentGroupSizes are different to the NumberGroupSizes?
Regardless of whether such a culture practically exists (if it doesn't, it may well come into existence in the future if the formatting for a culture is changed), I think that a better solution to the problem can be found if we consider these additional, special cases.
Here's a code snippet that shows a situation in which the other answers (based only on replacing the percent symbol) will fail, and a suggestion for how it could be done better properly:
// Modify a culture so that it has different decimal separators and group separators for numbers and percentages.
var customCulture = new CultureInfo("en-US")
{
NumberFormat = { PercentDecimalSeparator = "PDS", NumberDecimalSeparator = "NDS", PercentGroupSeparator = "PGS", NumberGroupSeparator = "NGS", PercentSymbol = "PS"}
};
// Set the current thread's culture to our custom culture
Thread.CurrentThread.CurrentCulture = customCulture;
// Create a percentage format string from a decimal value
var percentStringCustomCulture = 123.45m.ToString("p");
Console.WriteLine(percentStringCustomCulture); // renders "12PGS345PDS00 PS"
// Now just replace the percent symbol only, and try to parse as a numeric value (as suggested in the other answers)
var deceptiveNumericStringInCustomCulture = percentStringCustomCulture.Replace(customCulture.NumberFormat.PercentSymbol, string.Empty);
// THE FOLLOWING LINE THROWS A FORMATEXCEPTION
var decimalParsedFromDeceptiveNumericStringInCustomCulture = decimal.Parse(deceptiveNumericStringInCustomCulture);
// A better solution...replace the decimal separators and number group separators as well.
var betterNumericStringInCustomCulture = deceptiveNumericStringInCustomCulture.Replace(customCulture.NumberFormat.PercentDecimalSeparator, customCulture.NumberFormat.NumberDecimalSeparator);
// Here we mitigates issues potentially caused by group sizes by replacing the group separator by the empty string
betterNumericStringInCustomCulture = betterNumericStringInCustomCulture.Replace(customCulture.NumberFormat.PercentGroupSeparator, string.Empty);
// The following parse then yields the correct result
var decimalParsedFromBetterNumericStringInCustomCulture = decimal.Parse(betterNumericStringInCustomCulture)/100m;
Yes, the code is a bit longer, and perhaps I'm being pedantic (i.e. maybe such a culture will never actually exist). That said, it seems to me to be a more general solution. Hope it helps somebody :).
You could also combine the top two answers to avoid accepting invalid values while keeping it flexible for different cultures.
var num = double.Parse(value.TrimEnd(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PercentSymbol.ToCharArray() ) ) / 100d;
I'm not sure what it is with all this string replacement, substitution, and converters.
Use the NumberFormat Currency portion, but fill it with the percent formats from your required culture.
// input test value
string value = (.015m).ToString("P", CultureInfo.CurrentCulture);
// set up your format.
double doubleTest;
var numFormat = CultureInfo.CurrentCulture.NumberFormat;
NumberFormatInfo nfi = new NumberFormatInfo()
{
CurrencyDecimalDigits = numFormat.PercentDecimalDigits,
CurrencyDecimalSeparator = numFormat.PercentDecimalSeparator,
CurrencyGroupSeparator = numFormat.PercentGroupSeparator,
CurrencyGroupSizes = numFormat.PercentGroupSizes,
CurrencyNegativePattern = numFormat.PercentNegativePattern,
CurrencyPositivePattern = numFormat.PercentPositivePattern,
CurrencySymbol = numFormat.PercentSymbol
};
// load it.
if (double.TryParse(value, NumberStyles.Currency, nfi, out doubleTest))
{
doubleTest /= 100D;
// use as required.
}
Reflecting into .NET 4, here is Microsoft's implementation (found in System.Windows.Documents.ZoomPercentageConverter.ConvertBack). You can modify this to suit your needs. I alway's use MS's implementation when possible!
try
{
string str = (string) value;
if ((culture != null) && !string.IsNullOrEmpty(str))
{
str = ((string) value).Trim();
if ((!culture.IsNeutralCulture && (str.Length > 0)) && (culture.NumberFormat != null))
{
switch (culture.NumberFormat.PercentPositivePattern)
{
case 0:
case 1:
if ((str.Length - 1) == str.LastIndexOf(culture.NumberFormat.PercentSymbol, StringComparison.CurrentCultureIgnoreCase))
{
str = str.Substring(0, str.Length - 1);
}
break;
case 2:
if (str.IndexOf(culture.NumberFormat.PercentSymbol, StringComparison.CurrentCultureIgnoreCase) == 0)
{
str = str.Substring(1);
}
break;
}
}
num = Convert.ToDouble(str, culture);
flag = true;
}
}
catch (ArgumentOutOfRangeException)
{
}
catch (ArgumentNullException)
{
}
catch (FormatException)
{
}
catch (OverflowException)
{
}
You might vote for this .NET Framework 4 suggestion on Microsoft Connect: Extend double.Parse to interpret Percent values
It's a string, no matter what you do with it to remove the % sign you still have to parse it to a double.