Firefox pref is destroying JSON - javascript

I have the following JSON: http://pastebin.com/Sh20StJY
SO removed the chars on my post, so look at the link for the real JSON
which was generated using JSON.stringify and saved on Firefox prefs (pref.setCharPref(prefName, value);)
The problem is that when I save the value, Firefox does something that corrupts the JSON. If I try a JSON.parse retrieving the value from the config I get an error:
Error: JSON.parse: bad control character in string literal
If I try to validate the above JSON (which was retrieved from the settings) I get an error at line 20, the tokens value contains two invalid characters.
If I try a JSON.parse immediately after JSON.stringify the error doesn't occur.
Do I have to set something to save in a different encoding? How can I fix it?

nsIPrefBranch.getCharPref() only works for ASCII data, your JSON data contains some non-ASCII characters however. You can store Unicode data in preferences, it is merely a little bit more complicated:
var str = Components.classes["#mozilla.org/supports-string;1"]
.createInstance(Components.interfaces.nsISupportsString);
str.data = value;
pref.setComplexValue(prefName, Components.interfaces.nsISupportsString, str);
And to read that preference:
var str = pref.getComplexValue(prefName, Components.interfaces.nsISupportsString);
var value = str.data;
For reference: Documentation

Your JSON appears to contain non-ASCII characters such as ½. Can you check what encoding everything is being handled in?
nsIPrefBranch.setCharPref() assumes that its input is UTF-8 encoded, and the return value of nsIPrefBranch.getCharPref() is always an UTF-8 string. If your input is a bytestring or a character in some other encoding, you will either need to switch to UTF-8, or encode and decode it yourself when interacting with preferences.

I did this in one place to fix this issue:
(function overrideJsonParse() {
if (!window.JSON || !window.JSON.parse) {
window.setTimeout(overrideJsonParse, 1);
return; //this code has executed before JSON2.js, try again in a moment
}
var oldParse = window.JSON.parse;
window.JSON.parse = function (s) {
var b = "", i, l = s.length, c;
for (i = 0; i < l; ++i) {
c = s[i];
if (c.charCodeAt(0) >= 32) { b += c; }
}
return oldParse(b);
};
}());
This works in IE8 (using json2 or whatever), IE9, Firefox and Chrome.

The code seems correct. Try use single quotes '..': '...' instead of double quotes "..":"..." .

I still couldn't find the solution, but I found a workaround:
var b = "";
[].forEach.call("{ JSON STRING }", function(c, i) {
if (c.charCodeAt(0) >= 32)
b += c;
});
Now b is the new JSON, and might work...

Related

Convert string with '=' to JSON format

I am trying to convert a string i receive back from an API into a JSON object in Angular.
The issue is that the string is not normalized to be parsed into JSON easily.
This is the string im working with:
"{rootCause=EJBusinessException: This is a sample exception thrown for testing additional info field, description=This is a more detailed description about the incident., stackTrace=com.springboot.streams.infrastructure.web.heartbeat.HeartbeatService.testServiceNow(HeartbeatService.java:200)}"
When trying to do JSON.parse(myStr) it throws an error due to invalid string format.
Is there an easy way to convert the listed string into a more correct JSON format, getting rid of the '=' and replacing them with ':' instead.
There is more to it than just .replace(/['"]+/g, ''), as even with that the string is not ready to be turned into JSON yet.
Hoping someone more versed in Javascript knows a trick i dont.
You just need to manipulate the string before parsing it remove unecessary string that can cause error to the object like "{" and "}" and split it by "," example is in below.
var obj = {}, str = "{rootCause=EJBusinessException: This is a sample exception thrown for testing additional info field, description=This is a more detailed description about the incident., stackTrace=com.springboot.streams.infrastructure.web.heartbeat.HeartbeatService.testServiceNow(HeartbeatService.java:200)}"
str.split(",").forEach((st, i) => {
pair = st.split("=")
if(pair.length > 1) {
obj[pair[0].replace("{",'').replace("}", '').trim()] = pair[1]
} else {
obj[i] = pair
}
})
console.log(obj)
As commenters have posted, unless you control the API or at least have documentation that output will always follow a specific format, then you are limited in what you can do. With your current example, however you can trim off the extraneous bits to get the actual data... (remove braces, split on comma, split on equals) to get your key:value pairs... then build a javascript object from scratch with the data... if you need json string at that point can just JSON.stringify()
var initialString = "{rootCause=EJBusinessException: This is a sample exception thrown for testing additional info field, description=This is a more detailed description about the incident., stackTrace=com.springboot.streams.infrastructure.web.heartbeat.HeartbeatService.testServiceNow(HeartbeatService.java:200)}"
var trimmedString = initialString.substr(1, initialString.length - 2);
var pairArray = trimmedString.split(',');
var objArray = [];
pairArray.forEach(pair => {
var elementArray = pair.split('=');
var obj = {
key: elementArray[0].trim(),
value: elementArray[1].trim()
};
objArray.push(obj);
});
var returnObj = {};
objArray.forEach(element => {
returnObj[element.key] = element.value;
});
console.log(JSON.stringify(returnObj));

Retrieving binary data in Javascript (Ajax)

Im trying to get this remote binary file to read the bytes, which (of course) are supossed to come in the range 0..255. Since the response is given as a string, I need to use charCodeAt to get the numeric values for every character. I have come across the problem that charCodeAt returns the value in UTF8 (if im not mistaken), so for example the ASCII value 139 gets converted to 8249. This messes up my whole application cause I need to get those value as they are sent from the server.
The immediate solution is to create a big switch that, for every given UTF8 code will return the corresponding ASCII. But i was wondering if there is a more elegant and simpler solution. Thanks in advance.
The following code has been extracted from an answer to this StackOverflow question and should help you work around your issue.
function stringToBytesFaster ( str ) {
var ch, st, re = [], j=0;
for (var i = 0; i < str.length; i++ ) {
ch = str.charCodeAt(i);
if(ch < 127)
{
re[j++] = ch & 0xFF;
}
else
{
st = []; // clear stack
do {
st.push( ch & 0xFF ); // push byte to stack
ch = ch >> 8; // shift value down by 1 byte
}
while ( ch );
// add stack contents to result
// done because chars have "wrong" endianness
st = st.reverse();
for(var k=0;k<st.length; ++k)
re[j++] = st[k];
}
}
// return an array of bytes
return re;
}
var str = "\x8b\x00\x01\x41A\u1242B\u4123C";
alert(stringToBytesFaster(str)); // 139,0,1,65,65,18,66,66,65,35,67
I would recommend encoding the binary data is some character-encoding independent format like base64

How do I get the unicode/hex representation of a symbol out of the HTML using JavaScript/jQuery?

Say I have an element like this...
<math xmlns="http://www.w3.org/1998/Math/MathML">
<mo class="symbol">α</mo>
</math>
Is there a way to get the unicode/hex value of alpha α, &#x03B1, using JavaScript/jQuery? Something like...
$('.symbol').text().unicode(); // I know unicode() doesn't exist
$('.symbol').text().hex(); // I know hex() doesn't exist
I need &#x03B1 instead of α and it seems like anytime I insert &#x03B1 into the DOM and try to retrieve it right away, it gets rendered and I can't get &#x03B1 back; I just get α.
Using mostly plain JavaScript, you should be able to do:
function entityForSymbolInContainer(selector) {
var code = $(selector).text().charCodeAt(0);
var codeHex = code.toString(16).toUpperCase();
while (codeHex.length < 4) {
codeHex = "0" + codeHex;
}
return "&#x" + codeHex + ";";
}
Here's an example: http://jsfiddle.net/btWur/
charCodeAt will get you the decimal value of the string:
"α".charCodeAt(0); //returns 945
0x03b1 === 945; //returns true
toString will then get the hex string
(945).toString(16); // returns "3b1"
(Confirmed to work in IE9 and Chrome)
If you would try to convert Unicode character out of BMP (basic multilingual plane) in ways above - you are up for a nasty surprise. Characters out of BMP are encoded as multiple UTF16 values for example:
"🔒".length = 2 (one part for shackle one part for lock base :) )
so "🔒".charCodeAt(0) will give you 55357 which is only 'half' of number while "🔒".charCodeAt(1) will give you 56594 which is the other half.
To get char codes for those values you might wanna use use following string extension function
String.prototype.charCodeUTF32 = function(){
return ((((this.charCodeAt(0)-0xD800)*0x400) + (this.charCodeAt(1)-0xDC00) + 0x10000));
};
you can also use it like this
"&#x"+("🔒".charCodeUTF32()).toString(16)+";"
to get html hex codes.
Hope this saves you some time.
for example in case you need to convert this hex code to unicode
e68891e4bda0e4bb96
pick two character time by time ,
if the dec ascii code is over 127 , add a % before
return url decode string
function hex2a(hex) {
var str = '';
for (var i = 0; i < hex.length; i += 2){
var dec = parseInt(hex.substr(i, 2), 16);
character = String.fromCharCode(dec);
if (dec > 127)
character = "%"+hex.substr(i,2);
str += character;
}
return decodeURI(str);
}

Convert JavaScript String to be all lowercase

How can I convert a JavaScript string value to be in all lowercase letters?
Example: "Your Name" to "your name"
var lowerCaseName = "Your Name".toLowerCase();
Use either toLowerCase or toLocaleLowerCase methods of the String object. The difference is that toLocaleLowerCase will take current locale of the user/host into account. As per § 15.5.4.17 of the ECMAScript Language Specification (ECMA-262), toLocaleLowerCase…
…works exactly the same as toLowerCase
except that its result is intended to
yield the correct result for the host
environment’s current locale, rather
than a locale-independent result.
There will only be a difference in the
few cases (such as Turkish) where the
rules for that language conflict with
the regular Unicode case mappings.
Example:
var lower = 'Your Name'.toLowerCase();
Also note that the toLowerCase and toLocaleLowerCase functions are implemented to work generically on any value type. Therefore you can invoke these functions even on non-String objects. Doing so will imply automatic conversion to a string value prior to changing the case of each character in the resulting string value. For example, you can apply toLowerCase directly on a date like this:
var lower = String.prototype.toLowerCase.apply(new Date());
and which is effectively equivalent to:
var lower = new Date().toString().toLowerCase();
The second form is generally preferred for its simplicity and readability. On earlier versions of IE, the first had the benefit that it could work with a null value. The result of applying toLowerCase or toLocaleLowerCase on null would yield null (and not an error condition).
Yes, any string in JavaScript has a toLowerCase() method that will return a new string that is the old string in all lowercase. The old string will remain unchanged.
So, you can do something like:
"Foo".toLowerCase();
document.getElementById('myField').value.toLowerCase();
toLocaleUpperCase() or lower case functions don't behave like they should do. For example, on my system, with Safari 4, Chrome 4 Beta, and Firefox 3.5.x, it converts strings with Turkish characters incorrectly. The browsers respond to navigator.language as "en-US", "tr", "en-US" respectively.
But there isn't any way to get user's Accept-Lang setting in the browser as far as I could find.
Only Chrome gives me trouble although I have configured every browser as tr-TR locale preferred. I think these settings only affect the HTTP header, but we can't access to these settings via JavaScript.
In the Mozilla documentation it says "The characters within a string are converted to ... while respecting the current locale. For most languages, this will return the same as ...". I think it's valid for Turkish, and it doesn't differ if it's configured as en or tr.
In Turkish it should convert "DİNÇ" to "dinç" and "DINÇ" to "dınç" or vice-versa.
Just an example for toLowerCase(), toUpperCase() and a prototype for the not yet available toTitleCase() or toProperCase():
String.prototype.toTitleCase = function() {
return this.split(' ').map(i => i[0].toUpperCase() + i.substring(1).toLowerCase()).join(' ');
}
String.prototype.toPropperCase = function() {
return this.toTitleCase();
}
var OriginalCase = 'Your Name';
var lowercase = OriginalCase.toLowerCase();
var upperCase = lowercase.toUpperCase();
var titleCase = upperCase.toTitleCase();
console.log('Original: ' + OriginalCase);
console.log('toLowerCase(): ' + lowercase);
console.log('toUpperCase(): ' + upperCase);
console.log('toTitleCase(): ' + titleCase);
I paid attention that lots of people are looking for strtolower() in JavaScript. They are expecting the same function name as in other languages, and that's why this post is here.
I would recommend using a native JavaScript function:
"SomE StriNg".toLowerCase()
Here's the function that behaves exactly the same as PHP's one (for those who are porting PHP code into JavaScript)
function strToLower (str) {
return String(str).toLowerCase();
}
Methods or functions: toLowerCase() and toUpperCase()
Description: These methods are used to cover a string or alphabet from lowercase to uppercase or vice versa. E.g., "and" to "AND".
Converting to uppercase:
Example code:
<script language=javascript>
var ss = " testing case conversion method ";
var result = ss.toUpperCase();
document.write(result);
</script>
Result: TESTING CASE CONVERSION METHOD
Converting to lowercase:
Example Code:
<script language=javascript>
var ss = " TESTING LOWERCASE CONVERT FUNCTION ";
var result = ss.toLowerCase();
document.write(result);
</script>
Result: testing lowercase convert function
Explanation: In the above examples,
toUpperCase() method converts any string to "UPPER" case letters.
toLowerCase() method converts any string to "lower" case letters.
Note that the function will only work on string objects.
For instance, I was consuming a plugin, and was confused why I was getting a "extension.tolowercase is not a function" JavaScript error.
onChange: function(file, extension)
{
alert("extension.toLowerCase()=>" + extension.toLowerCase() + "<=");
Which produced the error "extension.toLowerCase is not a function". So I tried this piece of code, which revealed the problem!
alert("(typeof extension)=>" + (typeof extension) + "<=");;
The output was "(typeof extension)=>object<=" - so aha, I was not getting a string var for my input. The fix is straightforward though - just force the darn thing into a String!:
var extension = String(extension);
After the cast, the extension.toLowerCase() function worked fine.
Option 1: Using toLowerCase()
var x = 'ABC';
x = x.toLowerCase();
Option 2: Using your own function
function convertToLowerCase(str) {
var result = '';
for (var i = 0; i < str.length; i++) {
var code = str.charCodeAt(i);
if (code > 64 && code < 91) {
result += String.fromCharCode(code + 32);
} else {
result += str.charAt(i);
}
}
return result;
}
Call it as:
x = convertToLowerCase(x);
Simply use JS toLowerCase()
let v = "Your Name"
let u = v.toLowerCase(); or
let u = "Your Name".toLowerCase();
const str = 'Your Name';
// convert string to lowercase
const lowerStr = str.toLowerCase();
// print the new string
console.log(lowerStr);
In case you want to build it yourself:
function toLowerCase(string) {
let lowerCaseString = "";
for (let i = 0; i < string.length; i++) {
// Find ASCII charcode
let charcode = string.charCodeAt(i);
// If uppercase
if (charcode > 64 && charcode < 97) {
// Convert to lowercase
charcode = charcode + 32
}
// Back to char
let lowercase = String.fromCharCode(charcode);
// Append
lowerCaseString = lowerCaseString.concat(lowercase);
}
return lowerCaseString
}
You can use the in built .toLowerCase() method on JavaScript strings. Example:
var x = "Hello";
x.toLowerCase();
Try this short way:
var lower = (str+"").toLowerCase();
Try
<input type="text" style="text-transform: uppercase"> <!-- uppercase -->
<input type="text" style="text-transform: lowercase"> <!-- lowercase -->
Demo - JSFiddle

Detect difference between & and %26 in location.hash

Analyzing the location.hash with this simple javascript code:
<script type="text/javascript">alert(location.hash);</script>
I have a difficult time separating out GET variables that contain a & (encoded as %26) and a & used to separate variables.
Example one:
code=php&age=15d
Example two:
code=php%20%26%20code&age=15d
As you can see, example 1 has no problems, but getting javascript to know that "code=php & code" in example two is beyond my abilities:
(Note: I'm not really using these variable names, and changing them to something else will only work so long as a search term does not match a search key, so I wouldn't consider that a valid solution.)
There is no difference between %26 and & in a fragment identifier (‘hash’). ‘&’ is only a reserved character with special meaning in a query (‘search’) segment of a URI. Escaping ‘&’ to ‘%26’ need be given no more application-level visibility than escaping ‘a’ to ‘%61’.
Since there is no standard encoding scheme for hiding structured data within a fragment identifier, you could make your own. For example, use ‘+XX’ hex-encoding to encode a character in a component:
hxxp://www.example.com/page#code=php+20+2B+20php&age=15d
function encodeHashComponent(x) {
return encodeURIComponent(x).split('%').join('+');
}
function decodeHashComponent(x) {
return decodeURIComponent(x.split('+').join('%'));
}
function getHashParameters() {
var parts= location.hash.substring(1).split('&');
var pars= {};
for (var i= parts.length; i-->0;) {
var kv= parts[i].split('=');
var k= kv[0];
var v= kv.slice(1).join('=');
pars[decodeHashComponent(k)]= decodeHashComponent(v);
}
return pars;
}
Testing on Firefox 3.1, it looks as if the browser converts hex codes to the appropriate characters when populating the location.hash variable, so there is no way JavaScript can know how the original was a single character or a hex code.
If you're trying to encode a character like & inside of your hash variables, I would suggest replacing it with another string.
You can also parse the string in weird ways, like (JS 1.6 here):
function pairs(xs) {
return xs.length > 1 ? [[xs[0], xs[1]]].concat(pairs(xs.slice(2))) : []
}
function union(xss) {
return xss.length == 0 ? [] : xss[0].concat(union(xss.slice(1)));
}
function splitOnLast(s, sub) {
return s.indexOf(sub) == -1 ? [s] :
[s.substr(0, s.lastIndexOf(sub)),
s.substr(s.lastIndexOf(sub) + sub.length)];
}
function objFromPairs(ps) {
var o = {};
for (var i = 0; i < ps.length; i++) {
o[ps[i][0]] = ps[i][1];
}
return o;
}
function parseHash(hash) {
return objFromPairs(
pairs(
union(
location.hash
.substr(1)
.split("=")
.map(
function (s) splitOnLast(s, '&')))))
}
>>> location.hash
"#code=php & code&age=15d"
>>> parseHash(location.hash)
{ "code": "php & code", "age": "15d" }
Just do the same as you do with the first example, but after you have split on the & then call unescape() to convert the %26 to & and the %20 to a space.
Edit:
Looks like I'm a bit out of date and you should be using decodeURIComponent() now, though I don't see any clear explanation on what it does differently to unescape(), apart from a suggestion that it doesn't handle Unicode properly.
This worked fine for me:
var hash = [];
if (location.hash) {
hash = location.href.split('#')[1].split('&');
}

Categories

Resources