What is the difference between the JavaScript functions decodeURIComponent and decodeURI?
To explain the difference between these two let me explain the difference between encodeURI and encodeURIComponent.
The main difference is that:
The encodeURI function is intended for use on the full URI.
The encodeURIComponent function is intended to be used on .. well .. URI components that is
any part that lies between separators (; / ? : # & = + $ , #).
So, in encodeURIComponent these separators are encoded also because they are regarded as text and not special characters.
Now back to the difference between the decode functions, each function decodes strings generated by its corresponding encode counterpart taking care of the semantics of the special characters and their handling.
encodeURIComponent/decodeURIComponent() is almost always the pair you want to use, for concatenating together and splitting apart text strings in URI parts.
encodeURI in less common, and misleadingly named: it should really be called fixBrokenURI. It takes something that's nearly a URI, but has invalid characters such as spaces in it, and turns it into a real URI. It has a valid use in fixing up invalid URIs from user input, and it can also be used to turn an IRI (URI with bare Unicode characters in) into a plain URI (using %-escaped UTF-8 to encode the non-ASCII).
Where encodeURI should really be named fixBrokenURI(), decodeURI() could equally be called potentiallyBreakMyPreviouslyWorkingURI(). I can think of no valid use for it anywhere; avoid.
js> s = "http://www.example.com/string with + and ? and & and spaces";
http://www.example.com/string with + and ? and & and spaces
js> encodeURI(s)
http://www.example.com/string%20with%20+%20and%20?%20and%20&%20and%20spaces
js> encodeURIComponent(s)
http%3A%2F%2Fwww.example.com%2Fstring%20with%20%2B%20and%20%3F%20and%20%26%20and%20spaces
Looks like encodeURI produces a "safe" URI by encoding spaces and some other (e.g. nonprintable) characters, whereas encodeURIComponent additionally encodes the colon and slash and plus characters, and is meant to be used in query strings. The encoding of + and ? and & is of particular importance here, as these are special chars in query strings.
As I had the same question, but didn't find the answer here, I made some tests in order to figure out what the difference actually is.
I did this, since I need the encoding for something, which is not URL/URI related.
encodeURIComponent("A") returns "A", it does not encode "A" to "%41"
decodeURIComponent("%41") returns "A".
encodeURI("A") returns "A", it does not encode "A" to "%41"
decodeURI("%41") returns "A".
-That means both can decode alphanumeric characters, even though they did not encode them. However...
encodeURIComponent("&") returns "%26".
decodeURIComponent("%26") returns "&".
encodeURI("&") returns "&".
decodeURI("%26") returns "%26".
Even though encodeURIComponent does not encode all characters, decodeURIComponent can decode any value between %00 and %7F.
Note: It appears that if you try to decode a value above %7F (unless it's a unicode value), then your script will fail with an "URI error".
encodeURIComponent()
Converts the input into a URL-encoded
string
encodeURI()
URL-encodes the input, but
assumes a full URL is given, so
returns a valid URL by not encoding
the protocol (e.g. http://) and
host name (e.g.
www.stackoverflow.com).
decodeURIComponent() and decodeURI() are the opposite of the above
decodeURIComponent will decode URI special markers such as &, ?, #, etc, decodeURI will not.
encodeURIComponent
Not Escaped:
A-Z a-z 0-9 - _ . ! ~ * ' ( )
encodeURI()
Not Escaped:
A-Z a-z 0-9 ; , / ? : # & = + $ - _ . ! ~ * ' ( ) #
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI
Encode URI:
The encodeURI() method does not encodes:
, / ? : # & = + $ * #
Example
URI: https://my test.asp?name=ståle&car=saab
Encoded URI: https://my%20test.asp?name=st%C3%A5le&car=saab
Encode URI Component:
The encodeURIComponent() method also encodes:
, / ? : # & = + $ #
Example
URI: https://my test.asp?name=ståle&car=saab
Encoded URI: https%3A%2F%2Fmy%20test.asp%3Fname%3Dst%C3%A5le%26car%3Dsaab
For More: W3Schoools.com
Related
I have a problem where I need to preserve %2F in a URI string. However, encodeURI encodes % as %25 (as normal), so the whole string ends up being %252F instead of %2F. How can I escape this so the % doesn't get encoded. This is happening deep within a framework, so JS manipulation is not an option, it needs to be done via string escaping. I've tried using \ in a number of ways, none of it is working.
If you have control during the decode process, an unescape() before decodeURI would help.
This way, every double encoding is consistently handled.
For example:
decodeURIComponent(unescape("http%253A%252F%252Fabcd.com"));
will return
'http://abcd.com'
I'm not sure what this is called so I'm having trouble searching for it. How can I decode a string with unicode from http\u00253A\u00252F\u00252Fexample.com to http://example.com with JavaScript? I tried unescape, decodeURI, and decodeURIComponent so I guess the only thing left is string replace.
EDIT: The string is not typed, but rather a substring from another piece of code. So to solve the problem you have to start with something like this:
var s = 'http\\u00253A\\u00252F\\u00252Fexample.com';
I hope that shows why unescape() doesn't work.
Edit (2017-10-12):
#MechaLynx and #Kevin-Weber note that unescape() is deprecated from non-browser environments and does not exist in TypeScript. decodeURIComponent is a drop-in replacement. For broader compatibility, use the below instead:
decodeURIComponent(JSON.parse('"http\\u00253A\\u00252F\\u00252Fexample.com"'));
> 'http://example.com'
Original answer:
unescape(JSON.parse('"http\\u00253A\\u00252F\\u00252Fexample.com"'));
> 'http://example.com'
You can offload all the work to JSON.parse
UPDATE: Please note that this is a solution that should apply to older browsers or non-browser platforms, and is kept alive for instructional purposes. Please refer to #radicand 's answer below for a more up to date answer.
This is a unicode, escaped string. First the string was escaped, then encoded with unicode. To convert back to normal:
var x = "http\\u00253A\\u00252F\\u00252Fexample.com";
var r = /\\u([\d\w]{4})/gi;
x = x.replace(r, function (match, grp) {
return String.fromCharCode(parseInt(grp, 16)); } );
console.log(x); // http%3A%2F%2Fexample.com
x = unescape(x);
console.log(x); // http://example.com
To explain: I use a regular expression to look for \u0025. However, since I need only a part of this string for my replace operation, I use parentheses to isolate the part I'm going to reuse, 0025. This isolated part is called a group.
The gi part at the end of the expression denotes it should match all instances in the string, not just the first one, and that the matching should be case insensitive. This might look unnecessary given the example, but it adds versatility.
Now, to convert from one string to the next, I need to execute some steps on each group of each match, and I can't do that by simply transforming the string. Helpfully, the String.replace operation can accept a function, which will be executed for each match. The return of that function will replace the match itself in the string.
I use the second parameter this function accepts, which is the group I need to use, and transform it to the equivalent utf-8 sequence, then use the built - in unescape function to decode the string to its proper form.
Note that the use of unescape() is deprecated and doesn't work with the TypeScript compiler, for example.
Based on radicand's answer and the comments section below, here's an updated solution:
var string = "http\\u00253A\\u00252F\\u00252Fexample.com";
decodeURIComponent(JSON.parse('"' + string.replace(/\"/g, '\\"') + '"'));
http://example.com
Using JSON.decode for this comes with significant drawbacks that you must be aware of:
You must wrap the string in double quotes
Many characters are not supported and must be escaped themselves. For example, passing any of the following to JSON.decode (after wrapping them in double quotes) will error even though these are all valid: \\n, \n, \\0, a"a
It does not support hexadecimal escapes: \\x45
It does not support Unicode code point sequences: \\u{045}
There are other caveats as well. Essentially, using JSON.decode for this purpose is a hack and doesn't work the way you might always expect. You should stick with using the JSON library to handle JSON, not for string operations.
I recently ran into this issue myself and wanted a robust decoder, so I ended up writing one myself. It's complete and thoroughly tested and is available here: https://github.com/iansan5653/unraw. It mimics the JavaScript standard as closely as possible.
Explanation:
The source is about 250 lines so I won't include it all here, but essentially it uses the following Regex to find all escape sequences and then parses them using parseInt(string, 16) to decode the base-16 numbers and then String.fromCodePoint(number) to get the corresponding character:
/\\(?:(\\)|x([\s\S]{0,2})|u(\{[^}]*\}?)|u([\s\S]{4})\\u([^{][\s\S]{0,3})|u([\s\S]{0,4})|([0-3]?[0-7]{1,2})|([\s\S])|$)/g
Commented (NOTE: This regex matches all escape sequences, including invalid ones. If the string would throw an error in JS, it throws an error in my library [ie, '\x!!' will error]):
/
\\ # All escape sequences start with a backslash
(?: # Starts a group of 'or' statements
(\\) # If a second backslash is encountered, stop there (it's an escaped slash)
| # or
x([\s\S]{0,2}) # Match valid hexadecimal sequences
| # or
u(\{[^}]*\}?) # Match valid code point sequences
| # or
u([\s\S]{4})\\u([^{][\s\S]{0,3}) # Match surrogate code points which get parsed together
| # or
u([\s\S]{0,4}) # Match non-surrogate Unicode sequences
| # or
([0-3]?[0-7]{1,2}) # Match deprecated octal sequences
| # or
([\s\S]) # Match anything else ('.' doesn't match newlines)
| # or
$ # Match the end of the string
) # End the group of 'or' statements
/g # Match as many instances as there are
Example
Using that library:
import unraw from "unraw";
let step1 = unraw('http\\u00253A\\u00252F\\u00252Fexample.com');
// yields "http%3A%2F%2Fexample.com"
// Then you can use decodeURIComponent to further decode it:
let step2 = decodeURIComponent(step1);
// yields http://example.com
I don't have enough rep to put this under comments to the existing answers:
unescape is only deprecated for working with URIs (or any encoded utf-8) which is probably the case for most people's needs. encodeURIComponent converts a js string to escaped UTF-8 and decodeURIComponent only works on escaped UTF-8 bytes. It throws an error for something like decodeURIComponent('%a9'); // error because extended ascii isn't valid utf-8 (even though that's still a unicode value), whereas unescape('%a9'); // © So you need to know your data when using decodeURIComponent.
decodeURIComponent won't work on "%C2" or any lone byte over 0x7f because in utf-8 that indicates part of a surrogate. However decodeURIComponent("%C2%A9") //gives you © Unescape wouldn't work properly on that // © AND it wouldn't throw an error, so unescape can lead to buggy code if you don't know your data.
This is not an answer to this exact question, but for those who are hitting this page via a search result and who are trying to (like I was) construct a single Unicode character given a sequence of escaped codepoints, note that you can pass multiple arguments to String.fromCodePoint() like so:
String.fromCodePoint(parseInt("1F469", 16), parseInt("200D", 16), parseInt("1F4BC", 16)) // 👩💼
You can of course parse your string to extract the hex codepoint strings and then do something like:
let codePoints = hexCodePointStrings.map(s => parseInt(s, 16));
let str = String.fromCodePoint(...codePoints);
In my case, I was trying to unescape HTML file sth like
"\u003Cdiv id=\u0022app\u0022\u003E\r\n \u003Cdiv data-v-269b6c0d\u003E\r\n \u003Cdiv data-v-269b6c0d class=\u0022menu\u0022\u003E\r\n \u003Cdiv data-v-269b6c0d class=\u0022faux_column\u0022\u003E\r\n \u003Cdiv data-v-269b6c0d class=\u0022row\u0022\u003E\r\n \u003Cdiv data-v-269b6c0d class=\u0022col-md-12\u0022\u003E\r\n"
to
<div id="app">
<div data-v-269b6c0d>
<div data-v-269b6c0d class="menu">
<div data-v-269b6c0d class="faux_column">
<div data-v-269b6c0d class="row">
<div data-v-269b6c0d class="col-md-12">
Here below works in my case:
const jsEscape = (str: string) => {
return str.replace(new RegExp("'", 'g'),"\\'");
}
export const decodeUnicodeEntities = (data: any) => {
return unescape(jsEscape(data));
}
// Use it
const data = ".....";
const unescaped = decodeUnicodeEntities(data); // Unescaped html
I'm not sure what this is called so I'm having trouble searching for it. How can I decode a string with unicode from http\u00253A\u00252F\u00252Fexample.com to http://example.com with JavaScript? I tried unescape, decodeURI, and decodeURIComponent so I guess the only thing left is string replace.
EDIT: The string is not typed, but rather a substring from another piece of code. So to solve the problem you have to start with something like this:
var s = 'http\\u00253A\\u00252F\\u00252Fexample.com';
I hope that shows why unescape() doesn't work.
Edit (2017-10-12):
#MechaLynx and #Kevin-Weber note that unescape() is deprecated from non-browser environments and does not exist in TypeScript. decodeURIComponent is a drop-in replacement. For broader compatibility, use the below instead:
decodeURIComponent(JSON.parse('"http\\u00253A\\u00252F\\u00252Fexample.com"'));
> 'http://example.com'
Original answer:
unescape(JSON.parse('"http\\u00253A\\u00252F\\u00252Fexample.com"'));
> 'http://example.com'
You can offload all the work to JSON.parse
UPDATE: Please note that this is a solution that should apply to older browsers or non-browser platforms, and is kept alive for instructional purposes. Please refer to #radicand 's answer below for a more up to date answer.
This is a unicode, escaped string. First the string was escaped, then encoded with unicode. To convert back to normal:
var x = "http\\u00253A\\u00252F\\u00252Fexample.com";
var r = /\\u([\d\w]{4})/gi;
x = x.replace(r, function (match, grp) {
return String.fromCharCode(parseInt(grp, 16)); } );
console.log(x); // http%3A%2F%2Fexample.com
x = unescape(x);
console.log(x); // http://example.com
To explain: I use a regular expression to look for \u0025. However, since I need only a part of this string for my replace operation, I use parentheses to isolate the part I'm going to reuse, 0025. This isolated part is called a group.
The gi part at the end of the expression denotes it should match all instances in the string, not just the first one, and that the matching should be case insensitive. This might look unnecessary given the example, but it adds versatility.
Now, to convert from one string to the next, I need to execute some steps on each group of each match, and I can't do that by simply transforming the string. Helpfully, the String.replace operation can accept a function, which will be executed for each match. The return of that function will replace the match itself in the string.
I use the second parameter this function accepts, which is the group I need to use, and transform it to the equivalent utf-8 sequence, then use the built - in unescape function to decode the string to its proper form.
Note that the use of unescape() is deprecated and doesn't work with the TypeScript compiler, for example.
Based on radicand's answer and the comments section below, here's an updated solution:
var string = "http\\u00253A\\u00252F\\u00252Fexample.com";
decodeURIComponent(JSON.parse('"' + string.replace(/\"/g, '\\"') + '"'));
http://example.com
Using JSON.decode for this comes with significant drawbacks that you must be aware of:
You must wrap the string in double quotes
Many characters are not supported and must be escaped themselves. For example, passing any of the following to JSON.decode (after wrapping them in double quotes) will error even though these are all valid: \\n, \n, \\0, a"a
It does not support hexadecimal escapes: \\x45
It does not support Unicode code point sequences: \\u{045}
There are other caveats as well. Essentially, using JSON.decode for this purpose is a hack and doesn't work the way you might always expect. You should stick with using the JSON library to handle JSON, not for string operations.
I recently ran into this issue myself and wanted a robust decoder, so I ended up writing one myself. It's complete and thoroughly tested and is available here: https://github.com/iansan5653/unraw. It mimics the JavaScript standard as closely as possible.
Explanation:
The source is about 250 lines so I won't include it all here, but essentially it uses the following Regex to find all escape sequences and then parses them using parseInt(string, 16) to decode the base-16 numbers and then String.fromCodePoint(number) to get the corresponding character:
/\\(?:(\\)|x([\s\S]{0,2})|u(\{[^}]*\}?)|u([\s\S]{4})\\u([^{][\s\S]{0,3})|u([\s\S]{0,4})|([0-3]?[0-7]{1,2})|([\s\S])|$)/g
Commented (NOTE: This regex matches all escape sequences, including invalid ones. If the string would throw an error in JS, it throws an error in my library [ie, '\x!!' will error]):
/
\\ # All escape sequences start with a backslash
(?: # Starts a group of 'or' statements
(\\) # If a second backslash is encountered, stop there (it's an escaped slash)
| # or
x([\s\S]{0,2}) # Match valid hexadecimal sequences
| # or
u(\{[^}]*\}?) # Match valid code point sequences
| # or
u([\s\S]{4})\\u([^{][\s\S]{0,3}) # Match surrogate code points which get parsed together
| # or
u([\s\S]{0,4}) # Match non-surrogate Unicode sequences
| # or
([0-3]?[0-7]{1,2}) # Match deprecated octal sequences
| # or
([\s\S]) # Match anything else ('.' doesn't match newlines)
| # or
$ # Match the end of the string
) # End the group of 'or' statements
/g # Match as many instances as there are
Example
Using that library:
import unraw from "unraw";
let step1 = unraw('http\\u00253A\\u00252F\\u00252Fexample.com');
// yields "http%3A%2F%2Fexample.com"
// Then you can use decodeURIComponent to further decode it:
let step2 = decodeURIComponent(step1);
// yields http://example.com
I don't have enough rep to put this under comments to the existing answers:
unescape is only deprecated for working with URIs (or any encoded utf-8) which is probably the case for most people's needs. encodeURIComponent converts a js string to escaped UTF-8 and decodeURIComponent only works on escaped UTF-8 bytes. It throws an error for something like decodeURIComponent('%a9'); // error because extended ascii isn't valid utf-8 (even though that's still a unicode value), whereas unescape('%a9'); // © So you need to know your data when using decodeURIComponent.
decodeURIComponent won't work on "%C2" or any lone byte over 0x7f because in utf-8 that indicates part of a surrogate. However decodeURIComponent("%C2%A9") //gives you © Unescape wouldn't work properly on that // © AND it wouldn't throw an error, so unescape can lead to buggy code if you don't know your data.
This is not an answer to this exact question, but for those who are hitting this page via a search result and who are trying to (like I was) construct a single Unicode character given a sequence of escaped codepoints, note that you can pass multiple arguments to String.fromCodePoint() like so:
String.fromCodePoint(parseInt("1F469", 16), parseInt("200D", 16), parseInt("1F4BC", 16)) // 👩💼
You can of course parse your string to extract the hex codepoint strings and then do something like:
let codePoints = hexCodePointStrings.map(s => parseInt(s, 16));
let str = String.fromCodePoint(...codePoints);
In my case, I was trying to unescape HTML file sth like
"\u003Cdiv id=\u0022app\u0022\u003E\r\n \u003Cdiv data-v-269b6c0d\u003E\r\n \u003Cdiv data-v-269b6c0d class=\u0022menu\u0022\u003E\r\n \u003Cdiv data-v-269b6c0d class=\u0022faux_column\u0022\u003E\r\n \u003Cdiv data-v-269b6c0d class=\u0022row\u0022\u003E\r\n \u003Cdiv data-v-269b6c0d class=\u0022col-md-12\u0022\u003E\r\n"
to
<div id="app">
<div data-v-269b6c0d>
<div data-v-269b6c0d class="menu">
<div data-v-269b6c0d class="faux_column">
<div data-v-269b6c0d class="row">
<div data-v-269b6c0d class="col-md-12">
Here below works in my case:
const jsEscape = (str: string) => {
return str.replace(new RegExp("'", 'g'),"\\'");
}
export const decodeUnicodeEntities = (data: any) => {
return unescape(jsEscape(data));
}
// Use it
const data = ".....";
const unescaped = decodeUnicodeEntities(data); // Unescaped html
While passing my url, for example something:8000/something.jsp?param1=update¶m2=1000¶m3=SearchString%¶m4=3 , I am getting following error:
Bad Request
Your browser sent a request that this server could not understand.
I know SearchString% which I need to pass as a parameter, has the issue. Then how to pass a
parameter containing '%' in URL??
Use %25 in place of %
In URLs % has a special meaning as an escape character
Special characters like (space) can be encoded like %20 (the ascii code for space/32 in hex)
Therefore a percent sign itself must be encoded using the hex code for % which happens to be 25
You can use http://www.asciitable.com/ to look up the appropriate hex code under the hx column
Alternatively, if you are doing this programatically (ie. with javascript) you can use the builtin function escape() like escape('%')
See this: Encode URL in JavaScript?
Basically you need to make sure the variables you are passing are encoded (the '%' character is a special character in URL encoding).
Any special characters - %,?,&, etc... need to be encoded. They are encoded with '%' and their hex number. So '%' should become '%25', '&' becomes '%26', etc.
Update: see When are you supposed to use escape instead of encodeURI / encodeURIComponent? for why you should avoid using escape.
I'm having some issues trying to decode some javascript.. I have no idea what kind of encoding this is.. i tried base 64 decoders etc. If you can please help me out with this, here's a fragment of the code:
\x69\x6E\x6E\x65\x72\x48\x54\x4D\x4C","\x61\x70\x70\x34\x39\x34\x39\x3
Any ways I can get plain text from that?
Thanks!
\xNN is an escape sequence. NN is a hexidecimal number (00 to FF) that represents a Latin-1 character.
Escape sequences are interpreted literally within a string. So:
"\x69" === "i" // true
The escape() function encodes a
string.
This function makes a string portable,
so it can be transmitted across any
network to any computer that supports
ASCII characters.
This function encodes special
characters, with the exception of: * #
- _ + . /
The reverse of escape() is the unescape() function.
Try this:
alert(unescape("\x69\x6E\x6E\x65\x72\x48\x54\x4D\x4C\x61\x70\x70\x34\x39\x34\x39\x3"));
Edit: As J-P mentioned unescape isn't really needed here after all.
These are simply hex-values of symbols.
\x69 = i, etc. First several letters: "innerHTML", "ap…"
I think you should use window.unescape(), or unescape()