Regex to fetch string until the occurrence of a special character in javascript

Viewed 374

I have a string which looks like below

str = "I have candy='4' and ice cream = 'vanilla'"

I want to get terms to the left side of latest = and the terms should be fetched until the occurrence of another =.

So my string should be

leftOfEqual = "'4' and ice cream"

Another example

str = "I have candy='4' and ice cream = 'vanilla' and house='big'"

leftOfEqual = "'vanilla' and house"

This is my regex currently

leftOfEqual = str.match(/\S+(?= *=)/)[0]

But it looks at the first = and gives me only the immediate word to the left.

How can I do this?

NOTE: In case there is no presence = to the left of latest =, I should get the complete string till the beginning then.

5 Answers

Using split and slice to find the second to last split group.
lastIndexOf solution, to just search from the back. Find first =, then continue to the next =, slice between them.

str = "I have candy='4' and ice cream = 'vanilla'"
console.log(
str.split('=').slice(-2)[0]
)

console.log(
str.slice(str.lastIndexOf('=',x=str.lastIndexOf('=')-1)+1,x<-1?undefined:x)
)

str = "and ice cream = 'vanilla'"
console.log(
str.split('=').slice(-2)[0]
)

console.log(
str.slice(str.lastIndexOf('=',x=str.lastIndexOf('=')-1)+1,x<-1?undefined:x)
)

str = "I have cand'4' and ice cream 'vanilla'"
console.log(
str.split('=').slice(-2)[0]
)

console.log(
str.slice(str.lastIndexOf('=',x=str.lastIndexOf('=')-1)+1,x<-1?undefined:x)
)

You can probably try:

.*=(.*)=.*|(.*)=.*

Explanation of the above regex:

.* - Matches everything except a newline before a = symbol greedily.

= - Matches = literally.

=(.*)= - Represents a capturing group capturing everything between =. You can use multiple symbols if you want by using them as character classes something like [=%#].

|(.*)=.* - Represents an alternate capturing group representing left hand side of the equal sign in case there is no = after the latest =.

$1$2 - You can use this as the replacement option for replacing the complete string with the required output.

You can find the demo of the above regex in here.


Pictorial Representation

const regex = /.*=(.*)=.*|(.*)=.*/g;
const str = `"I have candy='4' and ice cream = 'vanilla'"
I have candy='4' and ice cream = 'vanilla' and house='big'
Regex is fun
Regex is beauty =
Regex is awesome = test test test
`;
const subst = `$1$2`;

// The substituted value will be contained in the result variable
const result = str.replace(regex, subst);
// You can use trim if you want to get rid of previous or after spaces.
console.log(result);

Ultimately I think you could just use split and reverse with an extra trim:

str = "I have candy='4' and ice cream = 'vanilla' and house='big'"
leftOfEqual = str.split('=').reverse()[1].trim();
console.log(leftOfEqual)


But must you use regex one could use a pattern like:

[^=]+(?==[^=]*$)

See the Online Demo

  • [^=]+ - Negated equal sign, one or more times
  • (?==[^=]*$) - Positive lookahead for equal sign followed by negated equal sign zero or more times up to end string ancor.

enter image description here


This should also tick:

"In case there is no presence = to the left of latest =, I should get the complete string till the beginning then."

In your current pattern \S+(?= *=) you are matching 1+ non whitespace chars and assert what is on the right is an equals sign.

You might also use a capturing group and match the last = at the end of the string.

If there is no group 1 value available, then return the match, matching any char except a newline or =. Else return the group 1 value.

^(?:.*=([^\r\n=]+)=[^=\r\n]+$|[^\r\n=]+)

Explanation

  • ^ Start of string
  • .*= Match any char except a newline 0+ times until the last occurrence of =
  • [^\s=]+ Match any char except - or a whitespace char
  • \s*=\s* Match = between optional whitespace chars
  • ( Capture group 1
    • [^\r\n=]+ Match 1+ times any char except = or a newline
  • ) Close group 1
  • =[^=\r\n]+$ Match the last = at the end of the string.
  • | Or
  • [^\r\n=]+ Match 1+ times any char except a newline or =

Regex demo

const pattern = /^(?:.*=([^\r\n=]+)=[^=\r\n]+$|[^\r\n=]+)/;
[
  "I have candy='4' and ice cream = 'vanilla'",
  "I have candy='4' and ice cream = 'vanilla' and house='big'",
  "test test ='test test test'"
].forEach(s => {
  console.log(s.match(pattern)[1] || s.match(pattern)[0]);
});

You can use lookaround

const findData = (str) => {
  let data = str.match(/(?<==)([^=]+)(?==[^=]*$)/)
  return data ? data[1].trim() : ''
}

let str1 = "I have candy='4' and ice cream = 'vanilla' and house='big'"
let str2 = "I have candy='4' and ice cream = 'vanilla'"

console.log(findData(str1))
console.log(findData(str2))

// You can use split as well

console.log(str1.split('=').slice(-2)[0].trim())
console.log(str2.split('=').slice(-2)[0].trim())

Related