javascript/jquery: quick way to retrieve numeric from length attributes - javascript

I have attributes which denotes "5 px", "8px" "6em" and possible some others which I currently cannot think of right now.
I'm interested in only the numeric value (ie 5, 8 or 6.) I know i can do some regex but I'm wondering is there a short, documented, cross browser and readable jquery / javascript function out there which already provides this?
regards,
Jeroen.
PS not sure if the wording in the title is correct please advice for alternatives.

Use parseInt function:
var str = '5px';
alert(parseInt(str, 10)); // 5
Note that second argument of 10 represents base 10 there.

In case they ever come back as 08px, (leading zero), use the radix of 10. Otherwise parseint() thinks your number is in octal.
var value = parseInt(str, 10);
It is probably never going to happen being returned from jQuery as a CSS property value, but a good habit to get into.

A combination of parseInt/parseFloat (see the other answers) is probably your best bet, but just for kicks (and if you want to make your code completely unreadable), you can always use a Regex with extra cheese:
+(str.match(/(-?\d+(?:\.\d+)?)/)||[,0])[1]
The + operator converts the result to a Number, ||[,0] provides a default array if there's no number in str. [,0] might not work in all browsers, but [0,0] will.
:)

Related

Javascript eval - obfuscation?

I came across some eval code:
eval('[+!+[]+!+[]+!+[]+!+[]+!+[]]');
This code equals the integer 5.
What is this type of thing called? I've tried searching the web but I can't seem to figure out what this is referred to. I find this very interesting and would like to know where/how one learns how to print different things instead of just the integer 5. Letters, symbols and etc. Since I can't pin point a pattern in that code I've had 0 success taking from and adding to it to make different results.
Is this some type of obfuscation?
This type of obfuscation, eval() aside, is known as Non-alphanumeric obfuscation.
To be completely Non-alphanumeric, the eval would have to be performed by Array constructor prototypes functions and subscript notation:
[]["sort"]["constructor"]("string to be evaled");
These strings are then converted to non-alphanumeric form.
AFAIK, it was first proposed by Yosuke Hosogawa around 2009.
If you want to see it in action see this tool: http://www.jsfuck.com/
It is not considered a good type of obfuscation because it is easy to reverse back to the original source code, without even having to run the code (statically). Plus, it increases the file size tremendously.
But its an interesting form of obfuscation that explores JavaScript type coercion. To learn more about it I recommend this presentation, slide 33:
http://www.slideshare.net/auditmark/owasp-eu-tour-2013-lisbon-pedro-fortuna-protecting-java-script-source-code-using-obfuscation
That's called Non-alphanumeric JavaScript and it's possible because of JavaScript type coercion capabilities. There are actually some ways to call eval/Function without having to use alpha characters:
[]["filter"]["constructor"]('[+!+[]+!+[]+!+[]+!+[]+!+[]]')()
After you replace strings "filter" and "constructor" by non-alphanumeric representations you have your full non-alphanumeric JavaScript.
If you want to play around with this, there is a site where you can do it: http://www.jsfuck.com/.
Check this https://github.com/aemkei/jsfuck/blob/master/jsfuck.js for more examples like the following:
'a': '(false+"")[1]',
'b': '(Function("return{}")()+"")[2]',
'c': '([]["filter"]+"")[3]',
...
To get the value as 5, the expression should have been like this
+[!+[] + !+[] + !+[] + !+[] + !+[]]
Let us analyze the common elements first. !+[].
An empty array literal in JavaScript is considered as Falsy.
+ operator applied to an array literal, will try convert it to a number and since it is empty, JavaScript will evaluate it to 0.
! operator converts 0 to true.
So,
console.log(!+[]);
would print true. Now, the expression can be reduced like this
+[true + true + true + true + true]
Since true is treated as 1 in arithmetic expressions, the actual expression becomes
+[ 5 ]
The + operator tries to convert the array ([ 5 ]) to a number and which results in 5. That is why you are getting 5.
I don't know of any term used to describe this type of code, aside from "abusing eval()".
I find this very interesting and would like to know where/how one
learns how to print different things instead of just the integer 5.
Letters, symbols and etc. Since I can't pin point a pattern in that
code I've had 0 success taking from and adding to it to make different
results.
This part I can at least partially answer. The eval() you pasted relies heavily on Javascript's strange type coercion rules. There are a lot of pages on the web describing various strange consequences of the coercion rules, which you can easily search for. But I can't find any reference on type coercion with the specific goal of getting "surprising" output from things like eval(), unless you count this video by Destroy All Software (the Javascript part starts at 1:20). Most of them understandably focus on how to avoid strange bugs in your code. For your purpose, I believe the most useful things I know of are:
The ! operator will convert anything to a boolean.
The unary + operator will convert anything to a number.
The binary + operator will coerce its arguments to either numbers or strings before adding or concatenating them. Normally it will only go with strings if one or the other argument is already a string, but there are exceptions.
The bitwise operators output integers, regardless of input.
Converting to numbers is complicated. Booleans will go to 0 or 1. Strings will attempt to use parseInt(), or produce NaN if that fails. I forget the rest.
Converting an object to a string or number will invoke its "toString" or "toValue" method respectively, if one exists.
You get the idea. thefourtheye's answer walks through exactly how these rules apply to the example you gave. I'm not even going to try summarizing what happens when Dates, Functions, and Regexps are involved.
Is this some type of obfuscation?
Normally you'd simply get obfuscation for free as part of minification, so I have no idea why someone would write that in real production code (assuming that's where you found it).

How to "unformat" a numerical string? JavaScript

So I know how to format a string or integer like 2000 to 2K, but how do I reverse it?
I want to do something like:
var string = "$2K".replace("/* K with 000 and remove $ symbol in front of 2 */");
How do I start? I am not very good regular expressions, but I have been taking some more time out to learn them. If you can help, I certainly appreciate it. Is it possible to do the same thing for M for millions (adding 000000 at the end) or B for billions (adding 000000000 at the end)?
var string = "$2K".replace(/\$(\d+)K/, "$1000");
will give output as
2000
I'm going to take a different approach to this, as the best way to do this is to change your app to not lose the original numeric information. I recognize that this isn't always possible (for example, if you're scraping formatted values...), but it could be useful way to think about it for other users with similar question.
Instead of just storing the numeric values or the display values (and then trying to convert back to the numeric values later on), try to update your app to store both in the same object:
var value = {numeric: 2000, display: '2K'}
console.log(value.numeric); // 2000
console.log(value.display); // 2K
The example here is a bit simplified, but if you pass around your values like this, you don't need to convert back in the first place. It also allows you to have your formatted values change based on locale, currency, or rounding, and you don't lose the precision of your original values.

How to delete "px" from 245px

Whats a simple way to delete the last two characters of a string?
To convert 245px in 245 just run:
parseInt('245px', 10);
It retains only leading numbers and discards all the rest.
use
var size = parseInt('245px', 10);
where 10 is the radix defining parseInt is parsing to a decimal value
use parseInt but don't use parseInt without a radix
The parseInt() function parses a string and returns an integer.
The signature is parseInt(string, radix)
The second argument forces parseInt to use a base ten numbering system.
The default input type for ParseInt() is decimal (base 10).
If the number begins in "0", it is assumed to be octal (base 8).
If it begins in "0x", it is assumed to be hexadecimal
why? if $(this).attr('num') would be "08" parsInt without a radix would become 0
To convert a pixel value without the "px" at the end. use parseFloat.
parseFloat('245px'); // returns 245
Note: If you use parseInt, the value will be correct if the value is an integer. If the value is a decimal one like 245.50px, then the value will be rounded to 245.
This does exactly what you ask: remove last two chars of a string:
s.substr(0, s.length-2);
Surprisingly, the substring method s.substr(0, s.length-2); is actually quite a bit faster for removing the px (yes it isn't as clean looking, and if there is a space it will remain -- "250px" -> "250" vs "250 px" -> "250 ").
If you want to account for spaces (which you probably should) then using the .trim() function will actually slow down the substr test enough that the parseInt method actually becomes superior.
An added benefit of using parseInt(s, 10) is that you also get a type conversion and can immediately start to apply it to mathematical functions.
So in the end, it really depends on what you plan on doing with the result.
If it is display only, then using the substr method without a trim would probably be your best bet.
If you're just trying to see if the value without px is the same as another value s.substr(0, s.length-2) == 0, then using the substr method would be best, as "250 " == 250 (even with the space) will result as true
If you want to account for the possibility of a space, add it to another value, or to compute something with it, then you may want to consider going with the parseInt route.
http://jsperf.com/remove-px-from-coord
The tests on jspref account for a space. I also tried a s.split('px')[0] and s.replace(/ *px/g, '') function, both found to be slower.
Feel free to add additional test cases.
Although parseInt() is a good option but still it is good to have many other solutions
var pixels = '245px';
Number(pixels.replace('px', ''));
substr() is now a legacy feature; use substring() instead: (syntax is the same in this case)
str.substring(0, str.length-2);
Or, use slice():
str.slice(0, -2);
slice() looks much cleaner, IMO. Negative values count back from the end.
Check http://www.w3schools.com/jsref/jsref_substr.asp
In your case would be something like
string.substr(0, string.length - 2)
I prefer:
"245px".replace(/px/,'')*1
since it's not surrounding the input.
Also, the *1 is for casting it to int.

Javascript toFixed localized?

Do you know if toFixed is a localized function?
I mean, will this:
var n = 100.67287;
alert(n.toFixed(2));
show "100.67" on english US OS/browsers
and "100,67" (with comma) on Italian OS/browsers?
(Italian or any other local system that uses comma as decimal separator).
Thanks!
Late addition: with Number.toLocaleString() now available on everything bar IE 10 & below, this works, albeit rather long-winded:
var n = 100.67287;
console.log(n.toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2
}));
Using undefined or 'default' for the language code will use the browser default language to format the number.
See developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString for full details.
If you're free to extend the Number prototype, you could defined Number.toLocaleFixed().
No, this will always return a point. The ECMA 262-spec [15.7.4.5] states it should be a point.
You can use this:
var n = 100.67287;
alert(parseFloat(n.toFixed(2)).toLocaleString());
On my german system the result is
100,67
No sadly, there is no real solution in pure jQuery/JavaScript. You'll need Globalize. The problem is that both toFixed() and toLocaleString() take a number and return a string. So you can never use them together. :( If you call foo.toFixed(2).toLocaleString() you won't get the localization (i.e. '1.234' in en should be '1,234' in fr) because its working on the result of toFixed() which is a string, not a number. :(

Javascript percentage validation

I am after a regular expression that validates a percentage from 0 100 and allows two decimal places.
Does anyone know how to do this or know of good web site that has example of common regular expressions used for client side validation in javascript?
#Tom - Thanks for the questions. Ideally there would be no leading 0's or other trailing characters.
Thanks to all those who have replied so far. I have found the comments really interesting.
Rather than using regular expressions for this, I would simply convert the user's entered number to a floating point value, and then check for the range you want (0 to 100). Trying to do numeric range validation with regular expressions is almost always the wrong tool for the job.
var x = parseFloat(str);
if (isNaN(x) || x < 0 || x > 100) {
// value is out of range
}
I propose this one:
(^100(\.0{1,2})?$)|(^([1-9]([0-9])?|0)(\.[0-9]{1,2})?$)
It matches 100, 100.0 and 100.00 using this part
^100(\.0{1,2})?$
and numbers like 0, 15, 99, 3.1, 21.67 using
^([1-9]([0-9])?|0)(\.[0-9]{1,2})?$
Note what leading zeros are prohibited, but trailing zeros are allowed (though no more than two decimal places).
This reminds me of an old blog Entry By Alex Papadimoulis (of The Daily WTF fame) where he tells the following story:
"A client has asked me to build and install a custom shelving system. I'm at the point where I need to nail it, but I'm not sure what to use to pound the nails in. Should I use an old shoe or a glass bottle?"
How would you answer the question?
It depends. If you are looking to pound a small (20lb) nail in something like drywall, you'll find it much easier to use the bottle, especially if the shoe is dirty. However, if you are trying to drive a heavy nail into some wood, go with the shoe: the bottle with shatter in your hand.
There is something fundamentally wrong with the way you are building; you need to use real tools. Yes, it may involve a trip to the toolbox (or even to the hardware store), but doing it the right way is going to save a lot of time, money, and aggravation through the lifecycle of your product. You need to stop building things for money until you understand the basics of construction.
This is such a question where most people sees it as a challenge to come up with the correct regular expression to solve the problem, but it would be much better to just say that using regular expressions are using the wrong tool for the job.
The problem when trying to use regex to validate numeric ranges is that it is hard to change if the requirements for the allowed range is changes. Today the requirement may be to validate numbers between 0 and 100 and it is possible to write a regex for that which doesn't make your eyes bleed. But next week the requirment maybe changes so values between 0 and 315 are allowed. Good luck altering your regex.
The solution given by Greg Hewgill is probably better - even though it would validate "99fxx" as "99". But given the circumstances that might actually be ok.
Given that your value is in str
str.match(/^(100(\.0{1,2})?|([0-9]?[0-9](\.[0-9]{1,2})))$/)
^100(\.(0){0,2})?$|^([1-9]?[0-9])(\.(\d{0,2}))?\%$
This would match:
100.00
optional "1-9" followed by a digit (this makes the int part), optionally followed by a dot and two digits
From what I see, Greg Hewgill's example doesn't really work that well because parseFloat('15x') would simply return 15 which would match the 0<x<100 condition. Using parseFloat is clearly wrong because it doesn't validate the percentage value, it tries to force a validation. Some people around here are complaining about leading zeroes and some are ignoring trailing invalid characters. Maybe the author of the question should edit it and make clear what he needs.
I recomend this, if you are not exclusively developing for english speaking users:
[0-9]{1,2}((,|\.)[0-9]{1,10})?%?
You can simply replace the 10 by a 2 to get two decimal places.
My example will match:
15.5
5.4366%
1,43
50,55%
34
45%
Of cause the output of this one is harder to cast, but something like this will do (Java Code):
private static Double getMyVal(String myVal) {
if (myVal.contains("%")) {
myVal = myVal.replace("%", "");
}
if (myVal.contains(",")) {
myVal = myVal.replace(',', '.');
}
return Double.valueOf(myVal);
}
None of the above solutions worked for me, as I needed my regex to allow for values with numbers and a decimal while the user is typing ex: '18.'
This solution allows for an empty string so the user can delete their entire input, and accounts for the other rules articulated above.
/(^$)|(^100(\.0{1,2})?$)|(^([1-9]([0-9])?|0)\.(\.[0-9]{1,2})?$)|(^([1-9]([0-9])?|0)(\.[0-9]{1,2})?$)/
(100|[0-9]{1,2})(\.[0-9]{1,2})?
That should be the regex you want. I suggest you to read Mastering Regular Expression and download RegexBuddy or The Regex Coach.
#mlarsen:
Is not that a regex here won't do the job better.
Remember that validation msut be done both on client and on server side, so something like:
100|(([1-9][0-9])|[0-9])(\.(([0-9][1-9])|[1-9]))?
would be a cross-language check, just beware of checking the input length with the output match length.
(100(\.(0){1,2})?|([1-9]{1}|[0-9]{2})(\.[0-9]{1,2})?)

Categories

Resources