3

It's easy to replace spaces with (say) underscores:

y = x.replace(/ /g, '_');

It's also easy to remove leading spaces:

y = x.replace(/^ +/, '');

But is there a good way to replace only the initial spaces with underscores?

Charles
  • 11,269
  • 13
  • 67
  • 105
  • 1
    @T.J.Crowder That replaces all of the spaces with a single underscore. I want to replace each of the leading spaces with an underscore. – Charles Mar 02 '18 at 14:54
  • Possible duplicate of [Javascript Regex- replace sequence of characters with same number of another character](https://stackoverflow.com/questions/7456559/javascript-regex-replace-sequence-of-characters-with-same-number-of-another-cha) – Sebastian Proske Mar 02 '18 at 15:10

3 Answers3

3

T.J. Crowder's answer is definitely better than this method, but I thought I would add it because it's only a matter of time until lookbehinds are supported in all major browsers. At the time of writing this answer, the V8 engine shipped in Chrome 62 and XS (January 17, 2018 update) are the only implementations of variable length lookbehinds in JavaScript as per EMCA TC39's regexp lookbehind proposal.

Note the regex below contains a trailing space. If you have Chrome 62+ (or if you're in the future; another browser that supports variable length lookbehinds) you can test the regex here.

(?<=^ *) 

const regex = /(?<=^ *) /g
const str = '        something is here'

console.log(str.replace(regex, '_'))
ctwheels
  • 21,901
  • 9
  • 42
  • 77
  • *"T.J. Crowder's answer is definitely better than this method..."* I beg to differ. :-) **Seriously cool.** And since look-behinds are Stage 4, that means they're in at least two implementations (probably V8 and SpiderMonkey) and they'll be in the ES2018 snapshot spec. – T.J. Crowder Mar 02 '18 at 15:18
  • @T.J.Crowder it's cool, but doesn't work on all browsers yet. Writing production code I'd still use your method :) – ctwheels Mar 02 '18 at 15:20
1

I want to replace each of the leading spaces with an underscore

To do that with just one replace call within the current spec,* you'd need the function call version of replace to do that, creating a string of underscores as long as the matched sequence of spaces:

y = x.replace(/^ +/, function(m) {
    return "_".repeat(m.length);
});

or with an ES2015+ arrow function:

y = x.replace(/^ +/, m => "_".repeat(m.length));

Live Example:

const x = "    four spaces";
const y = x.replace(/^ +/, m => "_".repeat(m.length));
console.log(y);

String.prototype.repeat was added in ES2015. If you need to support obsolete JavaScript engines, the MDN page has a polyfill you can use.


* But see ctwheels' answer using a feature from ES2018: Look-behinds. V. clever!

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
1

There's nothing wrong with combining your two regexes together:

var x = '     hello world';
var y = x.replace(/^ +/, u => u.replace(/ /g,  "_"));
console.log(y); // Outputs: ____hello world

A long hand version of the above would be:

var y = x.replace(/^ +/, function (u) { return u.replace(/ /g, "_"));

Essentially the outer regex/replace gets the initial spaces, the inner regex/replace replaces only those spaces with underscores.

Stephen Quan
  • 21,481
  • 4
  • 88
  • 75