I have a test for checking that an item is serialized correctly
public interface IMyJsIdentity
{
string Forename { get; }
string Surname { get; }
string Guid { get; }
}
public class MyIdentity : IMyJsIdentity
{
public string Forename { get; set; }
public string Surname { get; set; }
public string Guid { get; set; }
public int Id { get; set; }
}
[Fact]
public void SerialiseCorrectly()
{
// Arrange
MyIdentity identity = new MyIdentity()
{
Forename = "forename",
Surname = "surname",
Guid = "abcdefghijk"
};
// Act
string result = JsonConvert.SerializeObject(
identity,
new JsonSerializerSettings()
{
ContractResolver = new InterfaceContractResolver(typeof(IMyJsIdentity))
});
// Assert
result.Should().Be(
"{{\"Forename\":\"forename\",\"Surname\":\"surname\",\"Guid\":\"abcdefghijk\"}}"
);
}
However I get the following error on the test failure
Xunit.Sdk.AssertException: Expected string to be
"{{\"Forename\":\"forename\",\"Surname\":\"surname\",\"Guid\":\"abcdefghijk\"}}" with a length of 66, but
"{{\"Forename\":\"forename\",\"Surname\":\"surname\",\"Guid\":\"abcdefghijk\"}}" has a length of 64.
There's clearly something special that Json.net is doing to the string but I can't figure out what.
Weirdly this passes
result.Should().Be(
String.Format("{{\"Forename\":\"forename\",\"Surname\":\"surname\",\"Guid\":\"abcdefghijk\"}}")
);
I guess it's not a big deal but I'd like to know why.
I just tested and the value of result is:
{"Forename":"forename","Surname":"surname","Guid":"abcdefghijk","Id":0}
Which will naturally fail against your expected string of:
"{{\"Forename\":\"forename\",\"Surname\":\"surname\",\"Guid\":\"abcdefghijk\"}}"
Using double curly braces is an escape sequence only for format strings used in the String.Format method so that you may include a single brace. From the Composite Formatting MSDN page:
Opening and closing braces are interpreted as starting and ending a
format item. Consequently, you must use an escape sequence to display
a literal opening brace or closing brace. Specify two opening braces
("{{") in the fixed text to display one opening brace ("{"), or two
closing braces ("}}") to display one closing brace ("}").
If you aren't using String.Format, then the double brace will be interpreted literally as two braces as per the C# Specification 2.4.4.5 since it is not an escape character for string literals.
The resultant error message is confusing. I'm not sure if this is because how the debugger is reporting it to the GUI, or an error with how they are formatting their error message (perhaps they are overly aggressive escaping braces for output), or what.
If you change your test to be:
result.Should().Be(
"{\"Forename\":\"forename\",\"Surname\":\"surname\",\"Guid\":\"abcdefghijk\"}"
);
Then it will pass I suspect. This is backed up by your additional test using the String.Format call which changes your double braces to single braces. Now, if you intended to have double wrapping braces around your JSON, that's another issue entirely, but I suspect that that isn't your intent.
Related
public class Libro
{
public string Titolo { get; set; }
public string Autore { get; set; }
public string Editore { get; set; }
public int ISBN { get; set; }
public int Pagine { get; set; }
public decimal Prezzo { get; set; }
public int Quantità { get; set; }
not being all of type string, I would not know how to convert the int and decimal values to have as a result a table in which to display a list of books (titles, authors, publishers and price) that I have on a file.txt
public Libro BuildLibro(string input)
{
Libro result = null;
if (!String.IsNullOrEmpty(input))
{
var inputArray = input.Split('*');
if (inputArray.Length >= 6)
{
result = new Libro();
result.Titolo = inputArray[0];
result.Autore = inputArray[1];
result.Editore = inputArray[2];
if (!string.IsNullOrEmpty(inputArray[3]))
{
int.TryParse(inputArray[3], out int num);
result.ISBN= num;
}
if (!string.IsNullOrEmpty(inputArray[4]))
{
int.TryParse(inputArray[4], out int num);
result.Pagine = num;
}
if (!string.IsNullOrEmpty(inputArray[5]))
{
decimal.TryParse(inputArray[5], out decimal num);
result.Prezzo = num/100;
}
if (!string.IsNullOrEmpty(inputArray[6]))
{
int.TryParse(inputArray[6], out int num);
result.Quantità = num;
}
}
}
return result;
}
}
}
Foreword
The question has been edited massively since this answer was posted. I've advised that the edits should be reverted so this answer remains valid for the question as posted prior to the edit on Feb 14th (Revision 3), and a new question posted containing Rev 3's text
Original advice for Revision 2
You've switched tactic when you got to ISBN
ISBN = 4, Pagine = 5, Prezzo = 6, Quantità = 7
Assigning the editore name like this makes sense:
Editore = content[3]
It means "take the fourth element of the content array, which is a string array, and put it in the editors property, which is a string"
I guess you'll have tried the pattern of:
ISBN = content[4]
But this won't have worked out because content is full of strings and ISBN is an int and even if a string purely only full of numerical chars that doesn't mean it's a number. This will have given some error like "there is no implicit conversion..."
I guess then you removed the content and just left a hard coded 4 assigned as the ISBN which will work in that it will compile syntactically, but it is incorrect logically. That will just fix every ISBN at being 4, literally
Instead you should parse the string to an int. it's easy, and we can do it with like:
ISBN = int.Parse(content[4])
Similarly for the decimal there is a decimal.Parse
This may expose other problems like, if one of the values contains some non numerical chars (e.g. ISBNs that have hyphens in) but we can solve that later...
There are many ways to parse information out of a string.
I would sugest using regex. For example with the following regex you could parse three strings separated by a *:
(?'Title'[^*]+)[*](?'Author'[^*]+)[*](?'ISBN'[^*]+)
The Advantage of using regex is, that you check if the string is valid while the string is parsed.
To test a regex I would sugest to use something like https://regex101.com
In your code you can use the C# library:
using System.Text.RegularExpressions;
Regex rx = new Regex(#"(?'Title'[^*]+)[*](?'Author'[^*]+)[*](?'ISBN'[^*]+)",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
// Define a test string.
string text = "Harry Potter*Rowling*12345";
// Find matches.
MatchCollection matches = rx.Matches(text);
I have many classes and these classes have properties with attribute [WordColumn("Xxx", 1, typeof(string))]. E.g:
[JsonObject("Сотрудник")]
public class Person
{
[JsonProperty("firstName")]
[WordColumn("Имя", 1, typeof(string))]
public string FirstName { get; set; }
[JsonProperty("lastName")]
[WordColumn("Фамилия", 1)]
public string LastName { get; set; }
// ... other properties are omitted for the brevity
}
What I want is a regular expression that can delete all text that starts from [WordColumn and ends with )] and delete empty line which can be left after deletion.
I've tried to write the following regex and it finds all WordColumn:
\[WordColumn.*?\]
However, when I use it in Visual Studio with Find and Replace, then Replace in Files, tick Use Regular Expression, I leave Replace empty. Then after it leaves empty spaces after Replaces:
[JsonObject("Сотрудник")]
public class Person
{
[JsonProperty("firstName")]
// <- here the empty line remains
public string FirstName { get; set; }
[JsonProperty("lastName")]
// <- here the empty line remains
public string LastName { get; set; }
}
I am doing this in Visual Studio 2019 with Replace button.
Is it possible to remove this empty lines after [WordColumn...] was replaced?
Use the regex from #AndersonPimentel comment but with a small change (add ^[\t ]* to remove spaces)
^[\t ]*\[WordColumn.*?\]\r?\n
The proper regular expression for both, Visual Studio for Windows and for Mac, would be
\[WordColumn.*?\]\s*
I have an externally generated pipe deliminated file which I am trying to parse using .NET CSVHelper and enter into a SQL database but am finding a problem. The main issue is that there's quotes in the content but the delimiter is pipe and the quotes aren't escaped.
Imagine this being the file
ID|Price|Description|stock
133|55.89|Standard Electric Drill|23
134|3.40|3.5" Drill Bit|56
I've set the deliminater to pipe but it errors when it reaches a record with the quote ( in this case ID 134 with the quote " denoting inch) in the description. The error suggests setting BadDataFound to Null but that would just ignore the record?
Is there any configuration that I've missed that would allow this? Or is the best way simply to replace quotes with {quote} or something, parse it and then replace back before entering it into the database?
The NoEscape mode should work as long as no field contains a pipe or newline character.
void Main()
{
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
Mode = CsvMode.NoEscape,
Delimiter = "|"
};
using (var reader = new StringReader("ID|Price|Description|stock\n133|55.89|Standard Electric Drill|23\n134|3.40|3.5\" Drill Bit|56"))
using (var csv = new CsvReader(reader, config))
{
var records = csv.GetRecords<Foo>().Dump();
}
}
public class Foo
{
public int ID { get; set; }
public string Price { get; set; }
public string Description { get; set; }
public int stock { get; set; }
}
I'm trying to use the "!" special character in my C# class but my xml doesn't result in this "!MovieName" instead it results in " _x0021_MovieName "
I have tried to ! ; and also use CDATA but they dont work. They turn into a string of more x0021 (an example) types for each special character.
public class Movie
{
[XmlElement("!MovieName")]
public string Title
{ get; set; }
[XmlElement("MovieRating")]
public float Rating
{ get; set; }
[XmlElement("MovieReleaseDate")]
public DateTime ReleaseDate
{ get; set; }
}
An XML element name cannot begin with a ! which is why it's being replaced.
You should be able to start with:
Any letter
Underscore _
Colon :
See the XML Spec for more information, or more specifically the section on NameStartChar.
It's illegal to have a ! as the opening character of a tag in XML. You'll just have to use a different naming strategy.
Here is my property:
/// <summary>
/// The Business Unit
/// </summary>
[XmlAttribute("ows_Business_x0020_Unit")]
public string BusinessUnit { get; set; }
When I call Serialize on the object that has BusinessUnit I get:
ows_Business_x005F_x0020_Unit=\"Hi\"
Where does the _x005F come from?
It's an escape sequence. The _x0020 is actually another escape sequence for a space, so it's trying to escape the escape sequence so it doesn't get confused that you literally want the escape sequence, not the unescape value. So your attribute should look like this:
public class MyClass
{
[XmlAttribute("ows_Business Unit")]
public string BusinessUnit { get; set; }
}
That will serialize the attribute as ows_Business_x0020_Unit.
Microsoft encodes certain characters as _xZZZ_, so any names that look like _xZZZ_ get escaped. They chose to handle this by searching for "_x" and encoding the underscore as _x005F.
Your life will be easier if you avoid including "_x" in any of your names.