Mee
Mee

Reputation: 99

Dont allow to replace the match containing an odd amount of quotation marks

I am calling JS .replace() method on the following text that is within a variable:

if firstVar == 'string'
    alert firstVar
    alert 'string'

console.log 'string multiple words'
console.log 'string multiple words, then variable' + secVar
console.log firstVar + 'variable, then string multiple words'

This is how the replace method goes:

textVariableReplaced = textVariable.replace(/(^.*[a-zA-Z0-9]) ([a-zA-Z\/\('"].*$)/gm, '$1($2)');

This is the regex (^.*[a-zA-Z0-9]) ([a-zA-Z\/\('"].*$).

This regex should take letter or number([a-zA-Z0-9]), followed by a single space () (), then any text till the end of the line, that starts with a letter or ' or " or ( or / ([a-zA-Z\/\('"].*$).

This operation gives the following result:

if(firstVar == 'string')
    alert(firstVar)
    alert('string')

console.log 'string multiple(words')
console.log 'string multiple words, then(variable' + secVar)
console.log firstVar + 'variable, then string multiple(words')

Everything is perfect, except for the last lines.

The replace function should not put parentheses around the part of the text that contains an odd amount of quotation marks (' or "). So that the three last lines looked like this:

console.log('string multiple words')
console.log('string multiple words, then variable' + secVar)
console.log(firstVar + 'variable, then string multiple words')

Edit:

I have found this link to find out, whether the amount of characters is even or odd: How do you match even numbers of letter or odd numbers of letter using regexp for mysql

Edit 2:

Using the provided example in the link above I am trying to put ('')+ within the regex.

But, I am not sure how to implement it right.

Upvotes: 1

Views: 139

Answers (2)

Mee
Mee

Reputation: 99

Well, I have figured it out. It is a pretty interesting solution :) The desired REGEX goes as follows:

(^.*[a-zA-Z0-9]) (([a-zA-Z\/\(].*(('.*')+|(".*")+).*)|(['"].*('|").*)|([a-zA-Z\/\(][^'"\n]*)$)

Explanation:

(^.*[a-zA-Z0-9]) ( - as before, that takes the first part and the the first letter or number before the single space.

([a-zA-Z\/\(].*(('.*')+|(".*")+).*)| - any letter or / or (, followed by any amount of any characters, containing the even amount of single or double quotes, then any characters, then the OR statement

(['"].*('|").*)| - anything that starts and ends with single or double quotes, then any characters, then the OR statement

([a-zA-Z\/\(][^'"\n]*) - starts with any letter or / or (, followed by any characters that are not ' or " or a linebreak.

$) - the end of the line.

So this way,

textVariableReplaced = textVariable.replace(/(^.*[a-zA-Z0-9]) (([a-zA-Z\/\(].*(('.*')+|(".*")+).*)|(['"].*('|").*)|([a-zA-Z\/\(][^'"\n]*)$)/gm, '$1($2)');

wraps the text in parentheses, as needed.

Upvotes: 1

SamWhan
SamWhan

Reputation: 8332

The simple answer - put everything after the first word inside parentheses:

var input = "if firstVar == 'string'\n    alert firstVar\n    alert 'string'\n\nconsole.log 'string multiple words'\nconsole.log 'string multiple words, then variable' + secVar\nconsole.log firstVar + 'variable, then string multiple words'\n";

console.log(input.replace(/([^\s]+)\s*(.*)/g, '$1($2)'));

To complicate it (or make it more stable), you could work from something like this:

    var input = "if firstVar == 'string'\n    alert firstVar\n    alert 'string'\n\nconsole.log 'string multiple\" words'\nconsole.log 'string multiple words, then variable' + secVar;\nconsole.log firstVar + 'variable, then string multiple words'",
        re = /^(\s*[^\s]+)\s*((?:(['"])(?:(?!\3).)*['"]|(?:[^";\n\r]))*)/mg;

    console.log(input.replace(re, '$1($2)'));

It matches strings separately to keep quotes in pairs.

First it matches, and captures, the initial "command". Then matches, discarding, any white space. After that it captures anything up to a semi colon (;) or end of line, treating strings with matching quotes as a unit.

You haven't clearly defined the syntax of the input, so the semi colon part is just a shot from the hip ;)

Upvotes: 0

Related Questions