Leo Messi
Leo Messi

Reputation: 6186

Using regex to add styling to text

Having a text input, it is wanted to show the text in bold if it is situated between two exclamation signs.

For example: a!a!bb!c!c will be aabbcc. The text situated between ! will be made bold.

This is the code:

const arr = "this! i!s the i!npu!t";

if (arr.includes('!')) {
  result = arr.replace(/\!(\w+)\!/g, '<b>$1</b>');
}

it seems to work fine if there is a contiguous string but if there are words with spaces between them it doesn't work fine.

Is there a way to solve that?

Upvotes: 1

Views: 585

Answers (4)

The fourth bird
The fourth bird

Reputation: 163632

If this should not match ! ! to make a space bold <b> </b>, and to make the <b> start right before the first word character in ! <b>i</b>! you might also use 3 capturing groups.

If the exclamation marks should pair up, you can use a positive lookahead to assert optional pairs.

(!\s*)(\w+(?:\s+\w+)*)(\s*!)(?=(?:[^!]*![^!]*!)*[^!]*$)

Explanation

  • (!\s*) Capture group 1, match ! and optional whitespace chars
  • (\w+(?:\s*\w+)*) Capture group 2, match 1+ word chars and optionally repeat matching 1+ whitespace chars and 1+ word chars
  • (\s*!) Capture group 3, match optional whitespace chars and !
  • (?=(?:[^!]*![^!]*!)*[^!]*$) Positive lookahead, assert optional pairs of ! till the end of the string

Regex demo

If the match should be on the same line, you could exclude matching newlines in the negated character class using [^!\r\n], and use [^\S\r\n] to match spaces without newlines instead of \s

Regex demo

const regex = /(!\s*)(\w+(?:\s+\w+)*)(\s*!)(?=(?:[^!]*![^!]*!)*[^!]*$)/g;
[
  "this! i!s the i!npu!t",
  "! !",
  "a!a!bb!c!c",
  "a!b!c",
  "xyz",
].forEach(s => console.log(s.replace(regex, "$1<b>$2</b>$3")));

Upvotes: 0

Ryszard Czech
Ryszard Czech

Reputation: 18641

The issue is that \w does not match whitespace, it matches letters, digits and underscores. Use [\w\s] to match either a letter, digit, underscore or whitespace:

const arr = "this! i!s the i!npu!t";
const result = arr.replace(/!([\w\s]+)!/g, '<b>$1</b>');
console.log(result);

You can safely remove the arr.includes('!') check because .replace command will return unchanged string if no replacement occurs.

Upvotes: 0

Brian Drake
Brian Drake

Reputation: 346

It doesn’t work because you are using \w, which only matches certain characters, when you really want to match all characters other than !. The way to do that is to use [^!].

That is [^, followed by all the characters you do not want to match, followed by ].

Corrected code:

const arr = "this! i!s the i!npu!t";

if (arr.includes('!')) {
  result = arr.replace(/\!(\w+)\!/g, '<b>$1</b>');
}

Upvotes: 0

  1. First, you do not need to escape !.
  2. Second, you replace \w+ by [^!]+ because \w+ is egal [a-zA-Z0-9_]+.

So, you could try the following regex.

!([^!]+)!

const arr = "this! i!s the i!npu!t";

if (arr.includes('!')) {
  result = arr.replace(/!([^!]+)!/g, '<b>$1</b>');
}

console.log(result);

Upvotes: 4

Related Questions