2

So I got this string

'word word - word word 24/03/21'

And I would like to convert it to

'word_word-word_word_24_03_21'

I have tried this

replace(/[^aA-zZ0-9]/g, '_')

But I get this instead

word_word___word_word_24_03_21
Álvaro
  • 2,255
  • 1
  • 22
  • 48

4 Answers4

4

You can use 2 .replace() calls:

const s = 'word word - word word 24/03/21'
var r = s.replace(/\s*-\s*/g, '-').replace(/[^-\w]+/g, '_')

console.log(r)
//=> "word_word-word_word_24_03_21"

Explanation:

  • .replace(/\s*-\s*/g, '-'): Remove surrounding spaces of a hyphen
  • .replace(/[^-\w]+/g, '_'): Replace all character that are not a hyphen and not a word character with an underscore
anubhava
  • 761,203
  • 64
  • 569
  • 643
2

You can use

console.log(
  'word word - word word 24/03/21'.replace(/\s*(-)\s*|[^\w-]+/g, (x,y) => y || "_")
)

Here,

  • /\s*(-)\s*|[^\w-]+/g - matches and captures into Group 1 a - enclosed with zero or more whitespaces, and just matches any non-word char excluding -
  • (x,y) => y || "_") - replaces with Group 1 if it was matched, and if not, replacement is a _ char.
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
1

With a function for replace and an alternation in the pattern, you could also match:

  • (\s*-\s*) Match a - between optional whtiespace chars
  • | Or
  • [^a-zA-Z0-9-]+ Match 1+ times any of the listed ranges

In the callback, check if group 1 exists. If it does, return only a -, else return _

Note that this notation [^aA-zZ0-9] is not the same as [a-zA-Z0-9], see what [A-z] matches.

let s = "word word - word word 24/03/21";
s = s.replace(/(\s*-\s*)|[^a-zA-Z0-9-]+/g, (_, g1) => g1 ? "-" : "_");
console.log(s);
The fourth bird
  • 154,723
  • 16
  • 55
  • 70
0

You can use the + regex operator to replace 1 or more continuous matches at once.

let s = 'word word - word word 24/03/21';
let r = s
  .replace(/[^aA-zZ0-9]*-[^aA-zZ0-9]*/g, '-')
  .replace(/[^aA-zZ0-9-]+/g, '_');

console.log(r);
// 'word_word-word_word_24_03_21'
junvar
  • 11,151
  • 2
  • 30
  • 46