4

given a string such as one of the following:

'2'
'2px'
'2%'
'2em'
'2foobar'
'foobar'

I would like to determine:

1) whether it is a plain number (2 or 2.2), and if it is round it (Math.floor()) and append 'px' to it, so that, '2' or '2.2' becomes '2px'

2) if it's not a plain number determine if it is a valid css value, that is, if it consist of a number (int or float) followed by either 'px', 'em' or '%'. I know there are others but I'll just support those three. If it is, leave it.

3) if not, see if the string begins with a number (int ot float), round it and append 'px'

4) and if not, set it to an empty string

So that the result would be:

'2'     -> '2px'
'2.2'   -> '2px'

'2%'    -> '2%'
'2em'   -> '2em'

'2foo' -> '2px'

'foo'  -> ''

Is it possible to do this in a compact way (maybe using regex), or by using an existing css validator library for JS?

1
  • I've found this docs.jquery.com/Plugins/Validation .. will have a look at it to see how it could be extended to validate for the patterns I need here. Commented Apr 13, 2011 at 16:25

7 Answers 7

9

Here's how with a regex:

var input = '2.7em', output = parseInt(input, 10) + (input.match(/px|%|em/) || 'px')

edit:

var input = '2.7foo'
, number = parseInt(input, 10)
, output = (isNaN(number)) ? '': number + (input.match(/px|%|em/) || 'px');

edit 2: allow for float with em and %:

var inp='3.5em'
, n=parseFloat(inp), p=inp.match(/%|em/)
, output = (isNaN(n)) ? '': (p)?n+p:Math.round(n)+'px';
Sign up to request clarification or add additional context in comments.

2 Comments

Your example works, and I find it the most elegant for the given problem, but I get an error if the input.match does not find one of the patterns its looking for. If input is set to '10foo' I get an TypeError: No Prperties. See here ideone.com/cwlgI can you tweak it to fix this, then this would be a perfect solution.
this one also has the problem of converting floats to ints too early in the game.. floats should keep their decimals for inputs containing 'em' or '%'
2
var input  = '2foo';
var output = '';
var tmp;

tmp = parseInt( input.replace(/^[^1-9]*/, '') );
if ( tmp != 'NaN' ) {
  if ( tmp + '%' == input ) {
    output = tmp + '%';
  } else if ( tmp + 'em' == input ) {
    output = tmp + 'em';
  } else {
    output = tmp + 'px';
  }
}

4 Comments

super, parseInt really solves it all in one go here.. One thing to watch out for is that according to w3schools.com/jsref/jsref_parseInt.asp any leadning zeros should be striped from the input before processing, as that would trigger octal mode: parseInt('010') gives 8
I've edited my answer - it removes now everything from beginning that is not a 1-9 number.
this wont wok with floats. input =2.2em, tmp = 2, tmp+'em' != input so output = tmp+'px'
this is fixed in the modified version i posted below
1

Sure, you asked for an regular expression... Anyway, it's also possible by parsing the value as int or float and subtract it from the original value.

var input = '2.2px';
var value = parseInt(input, 10) // => 2
var unit = input.split(value)[1] // => 'px'

Comments

0

There are a few CSS parsers written in JS, not sure how robust they are at parsing numbers. Regex may be your best option.

https://github.com/stubbornella/parser-lib

Comments

0

Interesting problem. Here is a tested solution which uses one regex and a switch statement:

function clean_css_value(text) {
    var re = /^(\d+(?:\.\d*)?|\.\d+)([^\d\s]+)?$/m;
    // Case 0: String does not match pattern at all.
    if (!(m = text.match(re))) return '';
    // Case 1: No number at all? return '';
    if (!m[1]) return '';
    var i = Math.floor(m[1]); // Compute integer portion.
    // Case 2: Nothing after number? return integer pixels
    if (!m[2]) return i + 'px';
    switch (m[2]) {
    case 'em':
    case '%':
        return m[1] + m[2];
    case 'px':
    default:
        return i + 'px';
    }
}

Note that this function also works for fractional numbers having no integer portion, e.g. .2px.

Comments

0

Thought I would post the solution I'm using now. jus posted as answer to get the syntax coloring. The thing can be tested here: http://jsfiddle.net/385AY/2/

It's very lengthy, and some of the solutions here are much more compact.. but for anyone why may be able to use it, heres a version that is more accesible for beginners, and with comments..

function css_value_validate(input) {

    // first get rid of any whitespace at beginning or end of sting
    input = $.trim(input);

    // now catch any keywords that should be allowed
    // this could be expanded for lots of keyword 
    // by holding allowed words in an object and 
    // checking against them
    if (input == 'auto') {
        return input;
    }

    // now get rid of anything that may precede the first occurence of a number or a dot 
    input = input.replace(/^[^0-9\.]*/, '');

    // add a leading zero if the input starts with a . and then a number
    input = input.replace(/(^\.[0-9]*)/, "0$1");

    var output = '';
    var numeric;

    // check of the input is a straight zero or an empty string and 
    if (input + '' === '0' || input + '' === '') {
        return input;
    }

    // get the raw numeric by parsing to float
    numeric = parseFloat(input);
    if (numeric != 'NaN') {
        if (numeric + '%' === input) {
            output = numeric + '%';
        } else if (numeric + 'em' === input) {
            output = numeric + 'em';
        } else {
            // if converted to pixels strip any decimals.
            // the 2nd parameter, 10, is the radix making sure we parse in decimal
            output = parseInt(numeric, 10);
            output = (output > 0) ? output + unit : output;
        }
    }

    return output;
} // END cssvalidate()

1 Comment

I'm not sure which answer to choose here, could you please vote for you favorites, and add some comments, then I'll choose the most popular.. (only I can choose an answer right?)
-1

If you use this regex to replace your data, you only need to tackle the ones with the missing prefix.

^((?<whole>\d+)(\.\d+){0,1}(?<valid>px|em|pt|%){0,1}.*|.*)$

First, replace this with

${whole}${valid}

If the regex isn't matched, the 2nd part (|.*) will be matched (anything) and the match will be replaced with nothing.

You could also go a line by line aproach & remove that part, when there is no match, swap it out in javascript with ''.

Lastly, just do a quick replace using

^(?<justdigits>\d+)$

and replace with

${justdigits}px

So, in short: Lots of ways to go about this, up to you how to continue.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.