Convert cryptic string to a readable one with JavaScript (UTF-8) - javascript

I found out that when I save this distorted string ("Äußerungen üben") as an ANSI text file, then open it with Firefox and choose in the Firefox menu "Unicode", it turns it into a readable german format ("Äußerungen üben").
The same thing is possible with my text editor (Notepad++).
Is there any way to achieve this with JavaScript? E.g. the following would be nice:
var output = makeReadable("Äußerungen üben");
Unfortunately, I get this kind of distorted strings from an external source which doesn't care about UTF-8 and provides all data as ANSI.
PS: Saving the file as UTF-8 and setting the charset as UTF-8 in the META Tag has no effect.
Edit:
Now I solved it through making a list of all common UTF8/ANSI distortions (more than 1300) and wrote a function replacing all wrong character combinations with the right character. It works fine :-) .

I think the encoding of the "distorted string" in your question got munged further by posting it here. But a quick Google search for "javascript convert from utf-8" returns this blog post as the top hit:
http://ecmanaut.blogspot.com/2006/07/encoding-decoding-utf8-in-javascript.html
So it turns out that encoding and decoding UTF-8 in JavaScript is really easy. This works great for me:
var original = "Äußerungen üben";
var utf8 = unescape(encodeURIComponent(original));
//return utf8; // something like "ÃuÃerungen üben"
var output = decodeURIComponent(escape(utf8));
return output;

Related

Decoding Base64 String in Java

I'm using Java and I have a Base64 encoded string that I wish to decode and then do some operations to transform.
The correct decoded value is obtained in JavaScript through function atob(), but in java, using Base64.decodeBase64() I cannot get an equal value.
Example:
For:
String str = "AAAAAAAAAAAAAAAAAAAAAMaR+ySCU0Yzq+AV9pNCCOI="
With JavaScript atob(str) I get ->
"Æ‘û$‚SF3«àö“Bâ"
With Java new String(Base64.decodeBase64(str)) I get ->
"Æ?û$?SF3«à§ö?â"
Another way I could fixed the issue is to run JavaScript in Java with a Nashorn engine, but I'm getting an error near the "$" symbol.
Current Code:
ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
String script2 = "function decoMemo(memoStr){ print(atob(memoStr).split('')" +
".map((aChar) => `0${aChar.charCodeAt(0).toString(16)}`" +
".slice(-2)).join('').toUpperCase());}";
try {
engine.eval(script2);
Invocable inv = (Invocable) engine;
String returnValue = (String)inv.invokeFunction("decoMemo", memoTest );
System.out.print("\n result: " + returnValue);
} catch (ScriptException | NoSuchMethodException e1) {
e1.printStackTrace();
Any help would be appreciated. I search a lot of places but can't find the correct answer.
btoa is broken and shouldn't be used.
The problem is, bytes aren't characters. Base64 encoding does only one thing. It converts bytes to a stream of characters that survive just about any text-based transport mechanism. And Base64 decoding does that one thing in reverse, it converts such characters into bytes.
And the confusion is, you're printing those bytes as if they are characters. They are not.
You end up with the exact same bytes, but javascript and java disagree on how you're supposed to turn that into an ersatz string because you're trying to print it to a console. That's a mistake - bytes aren't characters. Thus, some sort of charset encoding is being used, and you don't want any of this, because these characters clearly aren't intended to be printed like that.
Javascript sort of half-equates characters and bytes and will freely convert one to the other, picking some random encoding. Oof. Javascript sucks in this regard, it is what it is. The MDN docs on btoa explains why you shouldn't use it. You're running into that problem.
Not entirely sure how you fix it in javascript - but perhaps you don't need it. Java is decoding the bytes perfectly well, as is javascript, but javascript then turns those bytes into characters into some silly fashion and that's causing the problem.
What you have there is not a text string at all. The giveaway is the AA's at the beginning. Those map to a number of zero bytes. That doesn't translate to meaningful text in any standard character set.
So what you have there is most likely binary data. Converting it to a string is not going to give you meaningful text.
Now to explain the difference you are seeing between Java and Javascript. It looks to me as if both Java and Javascript are making a "best effort" attempt to convert the binary data as if is was encoded in ISO-8859-1 (aka ISO LATIN-1).
The problem is some of the bytes codes are mapping to unassigned codes.
In the Java case those unassigned codes are being mapped to ?, either when the string is created or when it is being output.
In the Javascript case, either the unassigned codes are not included in the string, or them are being removed when you attempt to display them.
For the record, this is how an online base64 decoder the above for me:
����������������Æû$SF3«àöBâ
The unassigned codes are 0x91 0x82 and 0x93. 0x15 and 0x0B are non-printing control codes.
But the bottom line is that you should not be converting this data into a string in either Java or in Javascript. It should be treated as binary; i.e. an array of byte values.
byte[] data = Base64.getDecoder().decode(str);

Javascript encodeURI returns unexpected value

I have a problem URL-encoding a text with javascript.
I am in Germany, where we have these "Umlaute" (ÄÖÜ), and these letters make some problems.
An online encoder/decoder returned the following results for the word "Äpfel" (apples).
Äpfel >>> url-encode >>> %C3%84pfel
%C3%84pfel >>> url-decode >>> Äpfel
For testing, I created the following php.file (poc.php) with no php-content, just the javascript:
<script type="text/javascript">
var t = "Äpfel";
t = encodeURI(t);
alert(t);
t = decodeURI(t);
alert(t);
</script>
The first alert returns "%EF%BF%BDpfel", which differs from the result of the online encoder.
The second alert returns "�pfel" (yes, the diamond with the "?").
It seems that javascript cannot decode the text it just encoded.
I guess the cause of this behaviour is somewhere in the PHP settings. When I just rename the file from "poc.php" to "poc.html" the encoding is correct and the alerts return the same results as the online encoder/decoder.
When I check the current encoding, javascript and php return "utf-8".
In my "real" project I have a ".js" file included in my php-file (with the same problem).
<script type="text/javascript" src="scripts/functions.js"></script>
Has anybody an idea what causes this behaviour?
The weird byte stream %EF%BF%BD you're receiving is utf-8 version of the Unicode replacement character, that is, literally the � symbol.
The Javascript portion can url-decode the text it just url-encoded, it was just asked to encode the symbol for a missing symbol.
So: some part of your system is not using utf-8, but some other character set instead, and there's an unnecessary conversion done. My guess is that the file is encoded in latin-1, aka. ISO 8859-1, and PHP tries to read it as if it was UTF-8, converting the unrecognized character 0xc4 ('Ä' in latin-1) to the replacament character symbol.

Why special characters are automatically turning to someother characters in a string value?

My actual charcters:
ÆÐƎƏƐƔIJŊŒẞÞǷȜæðǝəɛɣijŋœĸſßþƿȝĄƁÇĐƊĘĦĮƘŁØƠŞȘŢȚŦŲƯY̨Ƴąɓçđɗęħįƙłøơşșţțŧųưy̨ƴÁÀÂÄǍĂĀÃÅǺĄÆǼǢƁĆĊĈČÇĎḌĐƊÐÉÈĖÊËĚĔĒĘẸƎƏƐĠĜǦĞĢƔáàâäǎăāãåǻąæǽǣɓćċĉčçďḍđɗðéèėêëěĕēęẹǝəɛġĝǧğģɣĤḤĦIÍÌİÎÏǏĬĪĨĮỊIJĴĶƘĹĻŁĽĿʼNŃN̈ŇÑŅŊÓÒÔÖǑŎŌÕŐỌØǾƠŒĥḥħıíìiîïǐĭīĩįịijĵķƙĸĺļłľŀʼnńn̈ňñņŋóòôöǒŏōõőọøǿơœŔŘŖŚŜŠŞȘṢẞŤŢṬŦÞÚÙÛÜǓŬŪŨŰŮŲỤƯẂẀŴẄǷÝỲŶŸȲỸƳŹŻŽẒŕřŗſśŝšşșṣßťţṭŧþúùûüǔŭūũűůųụưẃẁŵẅƿýỳŷÿȳỹƴźżžẓ
Above characters automatically turns into
’'‘ÆÃÆŽÆÆƔIJŊŒẞÞǷȜæðÇəɛɣijŋœĸſßþƿÈÄ„ÆÇÄƊĘĦĮƘÅØƠŞȘŢȚŦŲƯY̨Ƴąɓçđɗęħįƙłøơşșţțŧųưy̨ƴÃÀÂÄÇĂĀÃÅǺĄÆǼǢÆĆĊĈČÇĎḌÄÆŠÃÉÈĖÊËĚĔĒĘẸƎÆÆĠĜǦĞĢƔáàâäǎăÄãåǻąæǽǣɓćċĉÄçÄá¸Ä‘ɗðéèėêëěĕēęẹÇəɛġÄǧğģɣĤḤĦIÃÌİÎÃÇĬĪĨĮỊIJĴĶƘĹĻÅĽĿʼNŃN̈ŇÑŅŊÓÒÔÖǑŎŌÕÅỌØǾƠŒĥḥħıíìiîïÇĭīĩįịijĵķƙĸĺļłľŀʼnńn̈ňñņŋóòôöǒÅÅõőá»Ã¸Ç¿Æ¡Å“ŔŘŖŚŜŠŞȘṢẞŤŢṬŦÞÚÙÛÜǓŬŪŨŰŮŲỤƯẂẀŴẄǷÃỲŶŸȲỸƳŹŻŽẒŕřŗſśÅšşșṣßťţṭŧþúùûüǔŭūũűůųụưẃáºÅµáº…ƿýỳŷÿȳỹƴź
I got that output when i tried to console.log the string
That's not exactly a question, but it's obvious your file encodings are not what you expect them to be. Make sure everything is UTF-8 through and through.
Below code line, add between html head tags.
<meta charset="UTF-8"/>
1 - UTF-8 vs ANSI
Your first block is in UTF-8 format, and the second is encoded by ANSI.
Somewhere during your translation process, the strings changed from UTF-8 to ANSI. Make sure all your text sources are saved in UTF-8.
You can check with a free text editor like Notepad++ .
2 - Understand Javascript String codes
Each char has a given code, independently of what you think it's there.
For "special" chars, what it looks like a A might contain a different code from the default A.
A small example:
var letter1 = String.fromCharCode(65); // output: "A"
var letter2 = String.fromCharCode(913); // output: "Α"
console.log(letter1);
console.log(letter2);
console.log(letter1 === letter2);
So when you apply any logic to a string it will not give you the result you are expecting when the char code is not exactly the same.

JavaScript Encoding & Decoding Error

I am getting an issue with Javascript Encoding and Decoding. I have a json object which contains a string encoded in UTF-8 like 'R\xc3\xa9union'. To ensure that the Javascript file correctly displays the string, I'm adding an attribute charset to the script tag. The json object is in countries.js. I'm including countries.js as <script src="js/countries.js" charset="UTF-8"></script> and yet it is still being displayed as Réunion instead of Réunion. Any suggestion?
Use escape() combined with decodeURIComponent():
decodeURIComponent(escape('R\xc3\xa9union'));
That should do the trick:
escape('R\xc3\xa9union'); // "R%C3%A9union"
decodeURIComponent("R%C3%A9union"); // "Réunion"
Now, you said you couldn't do this manually for all the places you need strings from the JSON. I really don't know a way to automate this without re-building the JSON with JS, so I'd suggest writing a little "wrapper" function to decode on the fly:
function dc(str){
return decodeURIComponent(escape(str));
}
You can then decode the required strings with minimal effort:
var myString = dc(myJson["some"]["value"]);
Now, what else could work, but is a little more risky: JSON.stringify() the entire object, decode that using the 2 functions, then JSON.parse() it again.

Decode JSON string in Mojolicious that was encoded with JSON.stringify

I am trying to send javascript variable as JSON string to Mojolicious and I am having problems with decoding it on perl side. My page uses utf-8 encoding.
The json string (value of $self->param('routes_jsonstr')) seems to have correct value but Mojo::JSON can't decode it. The code is working well when there are no utf-8 characters. What am I doing wrong?
Javascript code:
var routes = [ {
addr1: 'Škofja Loka', // string with utf-8 character
addr2: 'Kranj'
}];
var routes_jsonstr = JSON.stringify(routes);
$.get(url.on_route_change,
{
routes_jsonstr: routes_jsonstr
}
);
Perl code:
sub on_route_change {
my $self = shift;
my $routes=j( $self->param('routes_jsonstr') );
warn $self->param('routes_jsonstr');
warn Dumper $routes;
}
Server output
Wide character in warn at /opt/mojo/routes/script/../lib/Routes/Homepage.pm line 76.
[{"addr1":"Škofja Loka","addr2":"Kranj"}] at /opt/mojo/routes/script/../lib/Routes/Homepage.pm line 76.
$VAR1 = undef;
Last line above shows that decoding of json string didn't work. When there are no utf-8 characters to decode on perl side everything works fine and $routes contain expected data.
Mojolicious style solution can be found here:
http://showmetheco.de/articles/2010/10/how-to-avoid-unicode-pitfalls-in-mojolicious.html
In Javascript I only changed $.get() to $.post().
Updated and working Perl code now looks like this:
use Mojo::ByteStream 'b';
sub on_route_change {
my $self = shift;
my $routes=j( b( $self->param('routes_jsonstr') )->encode('UTF-8') );
}
Tested with many different utf8 strings.
Wide character warnings happen when you print. This is not due to how you decode your unicode but your STDOUT encoding. Try use utf8::all available from CPAN which will set all your IO handles to utf8. Avoiding decoding probably isn't fixing the problem, but rather making it worse. The only reason it appears to work is your terminal is fixing things up for you.
You can take away at least some of the pain by escaping the problematic characters; see https://stackoverflow.com/a/4901205/17389.

Categories

Resources