String format and Formatted string - c#

I am trying to format a string lets say
"Hello george, how are you?"
I just want "george" in red color. Is there any way I can use String.Format and FormattedString side by side?
I tried using:
var text = new FormattedString();
text.Spans.Add(new Span {
Text = Localize.GetString("irs", String.Empty),
ForegroundColor = Colors.RedColor
});
label.FormattedText = String.Format(
Localize.GetString("instructions", String.Empty),
text
);
However this does not work. Is there any proper way to actually do this. I want localization so I don't want to split the text into multiple localization strings.

You can use an intercept provider in string.Format.
For illustrative purposes, I choose XAML format as output, and then convert it into FormattedString (but more concise formats like JSON can also be used).
First, let's implement the intercept provider - which will convert your string.Format's output into Span(s):
public class InterceptProvider : IFormatProvider, ICustomFormatter
{
public object GetFormat(Type formatType)
{
if (formatType == typeof(ICustomFormatter))
return this;
else
return null;
}
public string Format(String format, Object obj, IFormatProvider provider)
{
string spanText;
// Use default for all other formatting.
if (obj is IFormattable)
spanText = ((IFormattable)obj).ToString(format, System.Globalization.CultureInfo.CurrentCulture);
else
spanText = obj.ToString();
return $"</Span><Span ForegroundColor=\"Red\">{spanText}</Span><Span>";
}
}
Add an extension method to integrate the interceptor with string.Format.
public static class FormatExtensions
{
static ColorTypeConverter _typeConverter = new ColorTypeConverter();
static InterceptProvider _interceptor = new InterceptProvider();
public static string InterceptFormat(this string sourceStr, params object[] args)
{
return $"<FormattedString><Span>{string.Format(_interceptor, sourceStr, args)}</Span></FormattedString>";
}
And, finally an helper method that converts XAML to FormattedString object.
public static FormattedString ToFormattedString(this string xamlStr)
{
var toReturn = new FormattedString();
if (string.IsNullOrWhiteSpace(xamlStr))
return toReturn;
Span span = null;
using(var strReader = new StringReader(xamlStr))
{
using(var xmlReader = XmlReader.Create(strReader))
{
while (xmlReader.Read())
{
if (xmlReader.IsStartElement())
{
switch (xmlReader.Name)
{
case "Span":
span = new Span();
while (xmlReader.MoveToNextAttribute())
{
switch (xmlReader.Name)
{
case "ForegroundColor":
var color = xmlReader.Value;
if (!string.IsNullOrEmpty(color))
span.ForegroundColor = (Color)_typeConverter.ConvertFromInvariantString(color);
break;
}
}
if (xmlReader.IsStartElement() || xmlReader.MoveToContent() == XmlNodeType.Element)
{
span.Text = xmlReader.ReadString();
toReturn.Spans.Add(span ?? new Span());
}
break;
}
}
}
}
}
return toReturn;
}
USAGE:
label.FormattedText = Localize.GetString("instructions", String.Empty)
.InterceptFormat(text).ToFormattedString();
Or,
lbl.FormattedText = "{0} It is now {1:d} at {1:t}"
.InterceptFormat("Morning!", DateTime.Now)
.ToFormattedString();

Related

How to format a fixed length string

I have a fixed length string ABCDEFGHIJK, is there a way to convert this into AB-CDEFGHIJ-K using string format?
var s = "ABCDEFGHIJK";
Console.WriteLine($"{s[..2]}-{s[2..10]}-{s[^1..]}");
I have a fixed length string ABCDEFGHIJK, is there a way to convert
this into AB-CDEFGHIJ-K using string format?
Focusing on the "string format" part, we can implement IFormatProvider. This will format the string if it is EXACTLY eleven characters long, otherwise it just returns the same string back. Following the example, the "H" format stands for "hypenated":
private void button1_Click_2(object sender, EventArgs e)
{
string input = "ABCDEFGHIJK";
string output = String.Format(new MyStringFormat(), "Formatted: {0:H}", input);
Console.WriteLine(input);
Console.WriteLine(output);
}
public class MyStringFormat : IFormatProvider, ICustomFormatter
{
object IFormatProvider.GetFormat(Type formatType)
{
if (formatType == typeof(ICustomFormatter))
{
return this;
}
else
{
return null;
}
}
string ICustomFormatter.Format(string format, object arg, IFormatProvider formatProvider)
{
if (arg.GetType() != typeof(String))
{
try
{
return HandleOtherFormats(format, arg);
}
catch (FormatException e)
{
throw new FormatException(String.Format("The format of '{0}' is invalid.", format), e);
}
}
string ufmt = format.ToUpper(CultureInfo.InvariantCulture);
if (ufmt != "H")
{
try
{
return HandleOtherFormats(format, arg);
}
catch (FormatException e)
{
throw new FormatException(String.Format("The format of '{0}' is invalid.", format), e);
}
}
string result = arg.ToString();
if (result.Length != 11)
return result;
else
return result.Insert(2, "-").Insert(11, "-"); // see comment by Hans Passant!
}
private string HandleOtherFormats(string format, object arg)
{
if (arg is IFormattable)
return ((IFormattable)arg).ToString(format, CultureInfo.CurrentCulture);
else if (arg != null)
return arg.ToString();
else
return String.Empty;
}
}
howabout
var newstring = String.format("{0}-{1}-{2}", s.Substring(0,2), s.Substring(3,7), s.Substring(10,1))
you could also use interpolation and the new range stuff
var f = Regex.Replace("ABCDEFGHIJK", "^(..)(.*)(.)$", "$1-$2-$3");
...yeah, I know.
Also, dropping the {2}, etc. was inspired by Yuriy's answer here.
The Rube Goldberg way perhaps:
static void Main(string[] args)
{
string code = "ABCDEFGHIJK";
string mask = "##-########-#";
Console.WriteLine(code.Format(mask));
// AB-CDEFGHIJ-K
}
public static string Format(this string code, string mask, char token = '#')
{
StringBuilder sb = new StringBuilder(mask.Length);
int index = 0;
foreach (var item in mask)
{
if (item==token)
{
sb.Append(code[index++]);
}
else
{
sb.Append(item);
}
}
return sb.ToString();
}
Edit 1
replaced the space ' ' character placeholder with the pound sign '#' for better clarity.

detect format of date and convert it to exact format "yyyy-MM-dd"

I have method to convertDatefromExcelToSQL which take date value from excel file and convert it to exact format "yyyy-MM-dd"
the problem occured when date format in the PC different from the formate i declared
I want to modify my method to detect date format and convert it to exact format "yyyy-MM-dd"
public static string convertDatefromExcelToSQL(string excelDate)
{
string sdat = "";
DateTime dat;
sdat = ((string.IsNullOrEmpty(excelDate)) ? sdat : excelDate);
if (MIB.IsDouble(sdat))
{
dat = DateTime.FromOADate(double.Parse(sdat));
}
else
{
if (sdat.Contains(":"))
{
sdat = sdat.Split(' ')[0];
}
dat = DateTime.ParseExact(sdat, "dd/MM/yyyy", CultureInfo.InvariantCulture);
}
return dat.ToString("yyyy-MM-dd");
}
public static bool IsDouble(string text)
{
Double num = 0;
bool isDouble = false;
// Check for empty string.
if (string.IsNullOrEmpty(text))
{
return false;
}
isDouble = Double.TryParse(text, out num);
return isDouble;
}
public static string CDtStr(object v)
{
string lReturnValue = string.Empty;
DateTime lOutDateTime = new DateTime();
if (v != null)
{
if (v != DBNull.Value)
{
if (DateTime.TryParse(v.ToString(), out lOutDateTime))
lReturnValue = lOutDateTime.ToString("yyyy-MM-dd");
}
}
return lReturnValue;
}

Better way of writing json files in C# and validate the code

i have a lass like this
public class Params
{
public string FirstName;
public string SecondName;
public string Path;
public long Count;
public double TotalSize;
public long Time;
public bool HasError;
public Params()
{
}
public Params(string firstName, string secondName, string path, long count, double totalSize, long time, bool hasError)
{
FirstName = firstName;
SecondName = secondName;
Path = path;
Count = count;
TotalSize = totalSize;
Time = time;
HasError = hasError;
}
}
I have the json class like this:
public static class FileWriterJson
{
public static void WriteToJsonFile<T>(string filePath, T objectToWrite, bool append = true) where T : new()
{
TextWriter writer = null;
try
{
var contentsToWriteToFile = JsonConvert.SerializeObject(objectToWrite);
writer = new StreamWriter(filePath, append);
writer.Write(contentsToWriteToFile);
}
finally
{
if (writer != null)
writer.Close();
}
}
public static T ReadFromJsonFile<T>(string filePath) where T : new()
{
TextReader reader = null;
try
{
reader = new StreamReader(filePath);
var fileContents = reader.ReadToEnd();
return JsonConvert.DeserializeObject<T>(fileContents);
}
finally
{
if (reader != null)
reader.Close();
}
}
}
The main program is like this
var Params1 = new Params("Test", "TestSecondName", "Mypath",7, 65.0, 0, false);
FileWriterJson.WriteToJsonFile<Params>("C:\\Users\\myuser\\bin\\Debug\\test1.json", Params1);
FileWriterJson.WriteToJsonFile<Params>("C:\\Users\\myuser\\bin\\Debug\\test1.json", Params1);
This is mine test1.json:
{"FirstName":"Test","SecondName":"TestSecondName","Path":"Mypath","Count":7,"TotalSize":65.0,"Time":0,"HasError":false}{"FirstName":"Test","SecondName":"TestSecondName","Path":"Mypath","Count":7,"TotalSize":65.0,"Time":0,"HasError":false}
As you can see i have two json objects written in the file.
What i need to do is:
void ReadAllObjects(){
//read the json object from the file
// count the json objects - suppose there are two objects
for (int i=0;i<2;i++){
//do some processing with the first object
// if processing is successfull delete the object (i don't know how to delete the particular json object from file)
} }
but when i read like this
var abc =FileWriterJson.ReadFromJsonFile<Params>(
"C:\\Users\\myuser\\bin\\Debug\\test1.json");
i get the following error:
"Additional text encountered after finished reading JSON content: {.
Path '', line 1, position 155."
Then i used the following code to read the JSON file
public static IEnumerable<T> FromDelimitedJson<T>(TextReader reader, JsonSerializerSettings settings = null)
{
using (var jsonReader = new JsonTextReader(reader) { CloseInput = false, SupportMultipleContent = true })
{
var serializer = JsonSerializer.CreateDefault(settings);
while (jsonReader.Read())
{
if (jsonReader.TokenType == JsonToken.Comment)
continue;
yield return serializer.Deserialize<T>(jsonReader);
}
}
}
}
Which worked fine for me.
Now i need following suggestion:
1> when i put my test1.json data in https://jsonlint.com/ it says Error:
Parse error on line 9:
..."HasError": false} { "FirstName": "Tes
----------------------^
Expecting 'EOF', '}', ',', ']', got '{'
should i write into file in some other way.
2>Is there any better of doing this.
You are writing each object out individually to the file.
But what you are creating is not a valid JSON file, just a text file with individual JSON objects.
To make it valid JSON, then you need to put the objects into an array or list and then save this to the file.
var Params1 = new Params("Test", "TestFirstName", "Mypath",7, 65.0, 0, false);
var Params2 = new Params("Test 2", "TestSecondName", "Mypath",17, 165.0, 10, false);
List<Params> paramsList = new List<Params>();
paramsList .Add(Params1);
paramsList .Add(Params2);
FileWriterJson.WriteToJsonFile<List<Params>>("C:\\Users\\myuser\\bin\\Debug\\test1.json", paramsList);
FileWriterJson.WriteToJsonFile("C:\Users\myuser\bin\Debug\test1.json", Params1);
Then you should be able to read it in OK. Don't forget to read in a List<Params>

Ignoring Characters in a file read c#

I am reading a file for school and I am trying to ignore accents.
I used CultureInfo but it doesn't work for me is there another way??
(example .... Clémentine = clementine)
public static void SearchName()
{
string lineIn = String.Empty;
string[] BoatInfo = new string[5];
Console.WriteLine();
FileStream fs = new FileStream(#"FrenchMF.txt", FileMode.Open, FileAccess.Read);
StreamReader inputStream = new StreamReader(fs);
lineIn = inputStream.ReadLine();
string input = String.Empty;
Console.WriteLine();
Console.Write("Enter Vessel Name :");
input = Console.ReadLine().ToLower().Trim();
string CheckInput = String.Empty;
while(lineIn != null)
{
BoatInfo = lineIn.Split(',');
CheckInput = BoatInfo[0].ToLower();
if (input.Equals(CheckInput))
{
Console.WriteLine("its a Match" );
}
else
{
Console.WriteLine("No Match Found!! ");
return;
}
}
}
You can create an extension method for string:
public static string RemoveDiacritics(this string #this) {
var normalizedString = #this.Normalize(System.Text.NormalizationForm.FormD);
var stringBuilder = new StringBuilder();
foreach (var c in normalizedString) {
var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c);
if (unicodeCategory != UnicodeCategory.NonSpacingMark) {
stringBuilder.Append(c);
}
}
return stringBuilder.ToString().Normalize(NormalizationForm.FormC);
}
And then you can say input.RemoveDiacritics().
In order for the extension method to work, you must put it in a static class:
public static class ScorableExtensions {
public static string RemoveDiacritics(this string #this) {
//the one above
}
}
string.Compare(s1, s2, CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace);
See this answer
Of course, you can create your own CultureInfo - you do not have to use the CurrentCulture:
string.Compare(s1, s2, new CultureInfo("fr-FR"), CompareOptions.IgnoreNonSpace);

Derive Object Type from Format String

Is it possible to derive the intended object type from a .NET format string in C#? For example:
//Input parameters
var formatString = "dd/MM/yyyy"; //or "£0.00" for example
var stringValue = "2014-04-01"; //or "37.34" for example
//Logic
object value = null;
if (IsADate(formatString)) {
objectValue = DateTime.Parse(stringValue);
} else if (IsANumber(formatString)) {
objectValue = double.Parse(stringValue);
} else //etc
//Result
var resultString = String.Format(value,formatString);
I could obviously write out the IsADate() and IsANumber() functions, but wondered whether there is anything in the Framework that covers this already?
DateTime.TryParseExact() will make you your IsDate() function and Int32.TryParse() will make you your IsNumber() function.
Finally you should have something like that :
DateTime dateTime ;
int anInt;
if (DateTime.TryParseExact(formatString, stringValue , out dateTime)) {
objectValue = DateTime.Parse(stringValue);
} else if (Int32.TryParse(stringValue , out anInt)) {
objectValue = double.Parse(stringValue);
} else //etc
You could force .NET to try and parse your input given the format string where possible. If that succeeds, chances are good you got the right type:
var formatString = "dd/MM/yyyy"; //or "£0.00" for example
var stringValue = "2014-04-01"; //or "37.34" for example
//Logic
object value = null;
DateTime dtDummy;
int intDummy;
if (DateTime.TryParseExact(formatString, stringValue, out dtDummy)) {
value = dtDummy;
}
else
...
For some types (numeric types, for example) there's no such method.

Categories

Resources