views:

3326

answers:

4

What's a clean and efficient Javascript implementation to strip leading and trailing spaces from a string?

for example " dog", "dog ", " dog ", "           dog " all get turned into "dog"
+19  A: 

Use this:

if(typeof(String.prototype.trim) === "undefined")
{
    String.prototype.trim = function() 
    {
        return String(this).replace(/^\s+|\s+$/g, '');
    };
}

The trim function will now be available as a first-class function on your strings. For example:

" dog".trim() === "dog" //true

EDIT: Took J-P's suggestion to combine the regex patterns into one. Also added the global modifier per Christoph's suggestion.

Took Matthew Crumley's idea about sniffing on the trim function prior to recreating it. This is done in case the version of JavaScript used on the client is more recent and therefore has its own, native trim function.

David Andres
Why not combine the regex? /^\s\s*|\s\s*$/ ?
J-P
@J-P: Took your suggestion and edited the post.
David Andres
your regex is missing the `g` flag; also, see http://blog.stevenlevithan.com/archives/faster-trim-javascript for some performance data
Christoph
@Christoph: Added
David Andres
Another suggestion: String.prototype.trim is part of the upcoming ECMAScript 5 standard, so you could check if it already exists before you create it (`if (!String.prototype.trim) ...`). The built-in function is likely to be faster.
Matthew Crumley
@Matthew Crumley: Took your suggestion and added it to this post.
David Andres
to be compatible with the ECMA spec, `trim()` has to cast `this` to type string, ie you'll have to change `this.replace(...)` to `String(this).replace(...)` or `('' + this).replace(...)`; this allows to `call()` or `apply()` the function to non-string values
Christoph
@Christoph: do you mean to say within the String.prototype.trim() = ... function definition? I would have expected "this" to already refer to a string, as this is a prototypal function extending the String type.
David Andres
@David: yes, within the function; the ECMA spec allows `trim()` to be called on non-string objects, eg `String.prototype.trim.apply(42)` or `MyObj.prototype.trim = String.prototype.trim; new MyObj().trim();`
Christoph
@Christoph, can we get by by 42.toString() or 42 + ""?
David Andres
yes, but if you want to conform to the spec, you'll have to put the conversion into `trim()` (as I already explained 3 comments ago ;)); also, it's better to use `String(42)` instead of `42.toString()` as the former won't create an unneeded wrapper object and is the canonical way to cast to type string
Christoph
fixed the formatting and added the conversion; feel free to roll back if you don't like the changes
Christoph
@Christoph, cool. Still a bit confused as to why we need to cast this to a string within a String prototype where this should always be a string.
David Andres
@David: otherwise, `String.prototype.trim.apply(foo)` will throw an error if `foo` doesn't have a `replace()` method; the spec allows such a use: "The trim function is intentionally generic; it does not require that its `this` value be a String object. Therefore, it can be transferred to other kinds of objects for use as a method."
Christoph
@Christoph: I believe the only way for the "this" instance to not have a replace method, or at least to have a different replace method, would be due to user intervention (assigning a different function to the instance.replace property). In this case, I understand your point. I just want to be sure I understand your statement though, because I can't understand how a String would need to casted back to a String for any other reason than what I've written here.
David Andres
Note that `/\s/` will not strip all whitespace characters defined by ES3 spec. I recently wrote about the way browsers handle `/\s/` - http://thinkweb2.com/projects/prototype/whitespace-deviations/ - and how to work around it.
kangax
@kangax: Good to know.
David Andres
Curiously enough the original two-regex version (`replace(/^\s+/, '').replace(/\s+$/, '');`) is actually slightly faster in many browsers, so you shouldn't choose the one-regex version out of performance concerns. Pick whichever you find more readable.
bobince
@bobince: This makes sense. Alternation probably slows down the regex engine somewhat and there might be a lack of optimization for it.
David Andres
+4  A: 

Here's the function I use.

function trim(s){ 
  return ( s || '' ).replace( /^\s+|\s+$/g, '' ); 
}
Mic
+3  A: 

Steven Levithan once wrote about how to implement a Faster JavaScript Trim. It’s definitely worth a look.

Gumbo
A: 

If, rather than writing new code to trim a string, you're looking at existing code that calls "strip()" and wondering why it isn't working, you might want to check whether it attempts to include something like the prototypejs framework, and make sure it's actually getting loaded.
That framework adds a strip function to all String objects, but if e.g. you upgraded it and your web pages are still referring to the old .js file it'll of course not work.

Eric