Scenario
You have lots of XML files stored as UTF-16 in a Database or on a Server where space is not an issue. You need to take a large majority of these files that you need to get to other systems as XML Files and it is critical that you use as little space as you can.
Issue
In reality only about 10% of the files stored as UTF-16 need to be stored as UTF-16, the rest can safely be stored as UTF-8 and be fine. If we can have the ones that need to be UTF-16 be such, and the rest be UTF-8 we can use about 40% less space on the file system.
We have tried to use great compression of the data and this is useful but we find that we get the same ratio of compression with UTF-8 as we get with UTF-16 and UTF-8 compresses faster as well. Therefore in the end if as much of the data is stored as UTF-8 as possible we can not only save space when stored uncompress, we can still save more space even when it is compressed, and we can even save time with the compression itself.
Goal
To figure out when there are Unicode characters in the XML file that require UTF-16 so we can only use UTF-16 when we have to.
Some Details about XML File and Data
While we control the schema for the XML itself, we do not control what type of "strings" can go in the values from a Unicode perspective as the source is free to provide Unicode data to use. However, this is rare so we would like not to have to use UTF-16 everytime just to support something that is only needed 10% of the time.
Development Environment
We are using C# with the .Net Framework 4.0.
EDIT: Solution
The solution is just to use UTF-8.
The question was based on my misunderstanding of UTF and I appreciate everyone helping set me straight. Thank you!
Edit: I didn’t realise that your question implies that you think that there are Unicode strings that cannot be safely encoded as UTF-8. This is not the case. The following answer assumes that what you really meant was that some strings will simply be longer (take more storage space) as UTF-8.
I would say even less than 10% of the files need to be stored as UTF-16. Even if your XML contains significant amounts of Chinese, Japanese, Korean, or another language that is larger in UTF-8 than UTF-16, it is still only an issue if there is more text in that language than there is XML syntax.
Therefore, my initial intuition is “use UTF-8 until it’s a problem”. It makes for consistency, too.
If you have serious reason to believe that a large proportion of the XML will be East Asian, only then you need to worry about it. In that case, I would apply a simple heuristic, like... go through the XML and count the number of characters greater than U+0800 (those are three bytes in UTF-8) and only if this is greater than the number of characters less than U+0080 (those are one byte in UTF-8), use UTF-16.
Encode everything in UTF-8. UTF-8 can handle anything UTF-16 can, and is almost surely going to be smaller in the case of an XML document. The only case in which UTF-8 would be larger than UTF-16 would be if the file was largely composed of characters beyond the BMP, and in the best case (ASCII-spec, which includes every character you can type on a standard U.S. 104-key) a UTF-8 file would be half the size of a UTF-16.
UTF-8 requires 2 bytes or less per character for all symbols at or below ordinal U07FF, and one byte for any character in the Extended ASCII codepage; that means UTF-8 will be at least equal to UTF-16 in size (and probably far smaller) for any document in a modern-day language using the Latin, Greek, Cyrillic, Hebrew or Arabic alphabets, including most of the common symbols used in algebra and the IPA. That's known as the Base Multilingual Plane, and encompasses more than 90% of all official national languages outside of Asia.
UTF-16, as a general rule, will give you a smaller file for documents written primarily in the Devanagari (Hindi), Japanese, Chinese, or Hangul (Korean) alphabets, or any ancient or "esoteric" alphabet (Cherokee or Inuit anyone?), and MAY be smaller in cases of documents that heavily use specialized mathematical, scientific, engineering or game symbols. If the XML you're working with is for localization files for India, China and Japan, you MAY get a smaller file size with UTF-16, but you will have to make your program smart enough to know the localization file is encoded that way.
You never 'need' to use UTF-16 instead of UTF-8 and the choice is not about 'safety'. Both encodings have the same encodable character repertoire.
There is no such thing as a document that has to be UTF-16. Any UTF-16 document can also be encoded as UTF-8. It is theoretically possible to have a document which is larger as UTF-8 than as UTF-16, but this is vanishingly unlikely, and not worth stressing over.
Just encode everything as UTF-8 and stop worrying about it.
There are no characters that require UTF-16 rather than UTF-8. Both UTF-8 and UTF-16 (and for that matter, UTF-32 along with some other non-recommended formats) can encode the entire UCS (that's what UTF means).
There are some streams that will be smaller in UTF-16 than in UTF-8. However, in practice such streams will largely contain Asian ideographs which are linguistically very concise. However, XML requires some characters in the 0x20-0x7F range with specific meanings, and are quite often using alphabet-based scripts for the element and attribute names.
Because of the aforementioned concision of these ideographs, the ratio of XML tags (including the element and attribute name along with the less-thans and greater-thans) to human-trageted text will be much higher than in languages that use alphabets and syllabaries. For this reason, even in cases where plain-text in UTF-16 would be appreciably smaller than the same text in UTF-8, when it comes to XML either this difference will be less, or the UTF-8 will still be smaller.
As a rule, use UTF-8 for transmission and storage.
Edit: Just noticed that you're compressing too. In which case, the balance is even less important, just use UTF-8 and be done with it.
Related
I need to fit as much information as I can into a small file size. In this case, the data is in a comma separated format and all values are stored as 2dp decimals (no titles).
I've had a look and my understanding is that all the characters I need are stored using ASCII (1 byte per character) in my standard .txt file that I am currently using. Apparently ASCII has 256 possible values, which is way more than I need - I could get by with only 16 characters.
Could I save my data in some kind of 4bit text file? I will be creating the file using c# (all google searches result in advice on making a text file, not how to make a smaller "font" text). Would doing this save any space in the end anyway?
I could zip up anything before I send it, but any advice on ideas to get the filesize down would be greatly appreciated.
[the file] it will be read by a piece of c# code
You are therefore controlling the serialization format. You can pick any format you like.
A quick way to save space and reuse your existing code is to compress the CSV. Gzip is built-in but it is rather weak. You can use a 7-Zip library. The 7-Zip algorithm is state of the art. If will get rid of the redundancies caused by decimal points and by mostly using the characters 0-9. It will not remove 100% of that but 99%(?).
You can make this even more efficient by using a better format. You can use BinaryReader/Writer to easily write something entirely custom.
Protocol Buffers is a bit easier and also extremely compact.
I think that the question is legitimate, but the answer is that you impose logical conditions that leave no place for any solution.
So if you could avoid CSV structure for your custom structure you could save something, but you need it and it pretty much determines your solution. The only variable left is how do you encode the text, but you can't encode the text in less than 8 bits, you can just use higher values like Unicode (16 bits).
I won't comment on using compression as you already mentioned that you are looking for alternative answers and you are aware of that.
I have been searching on this topic for a while now, without finding any relevant answers. So thought of taking it on 'Stackoverflow' ...
We are trying to encode a string in order to pass it over a TCP/IP connection. Since ASN.1 is the most popular one to do it, so we are trying the various rules BER,DER,PER etc. to find out which one we can use. Our application is a .net based application and I was looking for freely available library which does this.
Strangely i could not find any free libraries.So, i started looking in the .Net framework itself. I found the there is only a 'BERConverter'. So, i did a small example with it. Taking an example string
string str = "The BER format specifies a self-describing and self-delimiting format for encoding ASN.1 data structures. Each data element is encoded as a type identifier, a length description, the actual data elements, and, where necessary, an end-of-content marker. These types of encodings are commonly called type-length-value or TLV encodings. This format allows a receiver to decode the ASN.1 information from an incomplete stream, without requiring any pre-knowledge of the size, content, or semantic meaning of the data"
In UTF-8 or ASCII it show as 512 bytes. I use the following code to encode it using BER
public static byte[] BerConvert(byte[] inputbytes)
{
byte[] output = BerConverter.Encode("{o}", inputbytes);
return output;
}
I get a byte array with size 522. In some of the other cases I find that the byte size increases compared to the original text. I thought encoding will decrease the size. Why is it happening like this ?
Apart from BER, are there other encoding rules like PER or DER which can be used to reduce the encoding size ? Are there any examples, libraries, or support which will help is implementing the these encoding styles?
When looking for ASN.1 Tools (free and commercial), a good place to start is the ITU-T web page http://www.itu.int/en/ITU-T/asn1/Pages/Tools.aspx that lists several. There are commercial tools listed there that support C#, but I do not see a free C# tool.
As for reduction of size of encodings, this depends significantly on the nature of your ASN.1 specification and the encoding rules used. If you are primarily sending text strings, BER and DER will not result in a reduction of the size of your message, while PER can significantly reduce the size of the message if you are able to produce a "permitted alphabet" constraint indicating a smaller set of characters permitted in the text you are sending.
You can try various encodings rules and different constraints to see the effects of your changes at the free online ASN.1 encoder decoder at http://asn1-playground.oss.com.
If you are beginning work on a new protocol, you may want to reevaluate your needs a bit.
As you probably know by now, ASN.1 comes with a bit of overhead—not just in the messaging, but in the engineering. A typical workflow involves writing a specification that describes the protocol, feeding it into a CASE tool that generates source code for an API, and then integrating the generated components into your application.
That said, some prefer a more ad-hoc approach. Microsoft has a BER converter class that you could try to use with C#: it may be suitable for your needs.
If compression is important, you may want to look into PER, as Paul said. But it's hard to produce valid PER encodings by hand because they rely on the specification to perform compression. (The permitted alphabet constraint is written into the specification and used to enumerate valid characters for shrinking the encoding.)
For more information on ASN.1 there are a number of tutorials online; you can also look at ITU-T standards X.680-X.695, which specify both the syntax notation and various encoding rules.
There are a few libraries on CodePlex. Like this one.
https://asn1.codeplex.com/SourceControl/latest#ObjectIdentifier.cs
I'll just leave it here Asn1DerParser.NET . And thank to the author for his work!
My question is simple: Are strings in .net encoding agnostic?
I ask this because when I ingest an xml file that I know was encoded with some windows-1252 code page elements (i.e smart quotes), in the debugger viewing the string that is holding my xml seems to want to resolve the single "smart quote" to a triangle with a question mark in it. This makes me wonder if .NET is asserting that the string that is holding my XML is UTF8 and therefore cannot resolve the difference.
This is a problem, if so, because if the string gets converted then my webservice that is meant to scrub the windows smart quotes from my text will fail because it doesn't recognize the triangle/question-mark-thingy.
Please help.
Strings are always UTF-16. Any incoming or outgoing data must be converted to/from that encoding.
If you use a proper XML reading library, it will most likely handle it for you, as long as the XML has the appropriate XML prolog (but Windows-1252 support is not required for compliance with the XML specification).
.NET uses UTF16 for all strings in memory (surrogate characters may be thrown in where need be).
When loading some text file it either defaults to interpreting the file as UTF-8 or whatever encoding you tell it to use.
Since you don't show any source code I can only speculate how you read/load the XML and if the XML has the proper charset in its prolog... depending on the method .NET will default to UTF-8 and represent that as UTF16 in memory...
Please provide more details if the above didn't help...
No, strings in .NET are stored as Unicode codepoints in a limited 16-bit range. For those that overflow, surrogate characters are used.
Do not confuse the above-mentioned in memory representation with storage representation which highly depends on the chosen encoding scheme.
The string class is (mostly) encoding-agnostic. You error comes from the process of decoding bytes to a string. This process does not work for you. You need to tell the decoder to use your special encoding.
Why are strings only mostly agnostic? That is because they encode unicode chars as sequences of 16-bit values. But although a 16 bit value has only 64k possible values, a unicode char can have about 1 million different values. Therefore an encoding process needs to happen as well. This happens through the use of surrogates. The string class is essentially UTF-16.
No. From MSDN:
A string is a sequential collection of Unicode characters . . .
My desktop c# application gets various documents from users, possibly in different encodings.
I need to show users existing documents, allow to manipulate them in my UI, and store them for future use.
Adding the notion of "encoding" to each of these steps seems complex to me. I was thinking to internally always convert the user input documents to UTF-8, and so my UI and data store do not need to worry about it. Then when the user wants the document back as a file I ask the user which encoding to use.
Does this make sense? Are encodings interoperable? What if I only support unicode?
In your application you should use native Unicode support (what the platform uses for storing Unicode). On Windows and OS X this is a sort of UTF-16, but on Linux it is UTF-8.
When it comes to saving/loading files or communicating with external systems, go for UTF-8.
Also, do not confuse code-pages with encodings.
Regarding code-pages, today I think it is not so important to support them anymore. At least it should not be a priority for you. Because for ANSI encodings you do not have BOMs, it will be really hard guess the encoding of files (in fact it is impossible to do it perfectly).
Encodings are not interoperable, since some have characters that others don't have.
Unicode internal representation is a good idea since it has the wider charset, but I'd advice to save back the document in the original encoding if the added characters are still in the said encoding. If not, prompt the user that you'll save in Unicode in order to encode correctly these characters.
Just decode all the documents to String. Strings in .Net are always Unicode (utf-16). Only use encodings when you are reading or writing a file.
When you get ANSI files you should know the codepage before converting to unicode e. g. create a utf-16 string, otherwise the bytes from 128 to 255 could result into the wrong unicode codepoints. You might get into trouble when you want to store unicode string to a ANSI file, because codepoints up to 0x10ffff cannot fit into a single byte.
There are only two reasons to ever use UTF-16 in an interchange format (that is, one that gets sent from A to B):
You didn't design the document type, and have to interoperate with something that already uses it.
Your content is of such that with some languages UTF-16 is shorter. This is relatively rare as even with those languages, there is often a high number of characters from the BMP in the mix, so UTF-8 ends up being more concise.
Barring that case, there are only two reasons to ever use anything other than UTF-8 in an interchange format:
You didn't design the document type, and have to interoperate with something that already uses legacy character sets.
You hate people.
Number 2 is particularly pressing if you particularly hate foreigners and people who don't use your own language, but if you just hate people generally, you'll cause enough headaches to enough people that you should find the exercise satisfying.
Now, extending from that, if a given document format designed by someone else allows UTF-8, and you can expect all modern software dealing with it to be able to handle UTF-8, then there are two reasons to not do this:
There is some sort of security checks done on the data to make sure it hasn't been changed (note, if you in any way edit or alter the document, this inherently doesn't apply).
You hate people. Again with a bonus for xenophobes.
For your internal storing, it's just a matter of whatever is most useful to you. As a rule, .NET tends to default to UTF-16 when in memory (char and string work with that) and UTF-8 when writing to and reading from strings. If your backing store is a SQL Server, then UTF-16 is your friend (the 'nchar', 'nvarchar', 'ntext' variants of 'char', 'varchar', 'text' to avoid issues if the character set was set to anything other than UTF-8), and other databases either have their own way of dealing with modern characters, or can use UTF-8.
In general though, use UTF-8 unless someone forces you to do otherwise (because either they were forced to deal with code from the 1990s or earlier, or because they hate people).
I have a web application that allows users to upload their content for processing. The processing engine expects UTF8 (and I'm composing XML from multiple users' files), so I need to ensure that I can properly decode the uploaded files.
Since I'd be surprised if any of my users knew their files even were encoded, I have very little hope they'd be able to correctly specify the encoding (decoder) to use. And so, my application is left with task of detecting before decoding.
This seems like such a universal problem, I'm surprised not to find either a framework capability or general recipe for the solution. Can it be I'm not searching with meaningful search terms?
I've implemented BOM-aware detection (http://en.wikipedia.org/wiki/Byte_order_mark) but I'm not sure how often files will be uploaded w/o a BOM to indicate encoding, and this isn't useful for most non-UTF files.
My questions boil down to:
Is BOM-aware detection sufficient for the vast majority of files?
In the case where BOM-detection fails, is it possible to try different decoders and determine if they are "valid"? (My attempts indicate the answer is "no.")
Under what circumstances will a "valid" file fail with the C# encoder/decoder framework?
Is there a repository anywhere that has a multitude of files with various encodings to use for testing?
While I'm specifically asking about C#/.NET, I'd like to know the answer for Java, Python and other languages for the next time I have to do this.
So far I've found:
A "valid" UTF-16 file with Ctrl-S characters has caused encoding to UTF-8 to throw an exception (Illegal character?) (That was an XML encoding exception.)
Decoding a valid UTF-16 file with UTF-8 succeeds but gives text with null characters. Huh?
Currently, I only expect UTF-8, UTF-16 and probably ISO-8859-1 files, but I want the solution to be extensible if possible.
My existing set of input files isn't nearly broad enough to uncover all the problems that will occur with live files.
Although the files I'm trying to decode are "text" I think they are often created w/methods that leave garbage characters in the files. Hence "valid" files may not be "pure". Oh joy.
Thanks.
There won't be an absolutely reliable way, but you may be able to get "pretty good" result with some heuristics.
If the data starts with a BOM, use it.
If the data contains 0-bytes, it is likely utf-16 or ucs-32. You can distinguish between these, and between the big-endian and little-endian variants of these by looking at the positions of the 0-bytes
If the data can be decoded as utf-8 (without errors), then it is very likely utf-8 (or US-ASCII, but this is a subset of utf-8)
Next, if you want to go international, map the browser's language setting to the most likely encoding for that language.
Finally, assume ISO-8859-1
Whether "pretty good" is "good enough" depends on your application, of course. If you need to be sure, you might want to display the results as a preview, and let the user confirm that the data looks right. If it doesn't, try the next likely encoding, until the user is satisfied.
Note: this algorithm will not work if the data contains garbage characters. For example, a single garbage byte in otherwise valid utf-8 will cause utf-8 decoding to fail, making the algorithm go down the wrong path. You may need to take additional measures to handle this. For example, if you can identify possible garbage beforehand, strip it before you try to determine the encoding. (It doesn't matter if you strip too aggressive, once you have determined the encoding, you can decode the original unstripped data, just configure the decoders to replace invalid characters instead of throwing an exception.) Or count decoding errors and weight them appropriately. But this probably depends much on the nature of your garbage, i.e. what assumptions you can make.
Have you tried reading a representative cross-section of your files from user, running them through your program, testing, correcting any errors and moving on?
I've found File.ReadAllLines() pretty effective across a very wide range of applications without worrying about all of the encodings. It seems to handle it pretty well.
Xmlreader() has done fairly well once I figured out how to use it properly.
Maybe you could post some specific examples of data and get some better responses.
This is a well known problem. You can try to do what Internet Explorer is doing. This is a nice article in The CodeProject that describes Microsoft's solution to the problem. However no solution is 100% accurate as everything is based on heuristcs. And it is also no safe to assume that a BOM will be present.
You may like to look at a Python-based solution called chardet. It's a Python port of Mozilla code. Although you may not be able to use it directly, its documentation is well worth reading, as is the original Mozilla article it references.
I ran into a similar issue. I needed a powershell script that figured out if a file was text-encoded ( in any common encoding ) or not.
It's definitely not exhaustive, but here's my solution...
PowerShell search script that ignores binary files