1

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.

Mee
  • 99
  • 9
  • You won't be able to evaluate balanced constructs (a great course [here](https://stackoverflow.com/a/3644267/8767753)) using javascript RegExp: no recursion, no balancing groups, and nested references working weirdly. You better use a parser. – PJProudhon Feb 20 '18 at 14:16
  • So what is this regex supposed to be doing? I can't figure it out from your question – Liam Feb 20 '18 at 14:18
  • @PJProudhon There is always a way. I have even thought in the beginning, that I wouldnt be able to make it work the way it is working right now. – Mee Feb 20 '18 at 14:18
  • @Liam Compare the examples of initial, processed and desired code. It should put prantheses around the desired match – Mee Feb 20 '18 at 14:19
  • Why is this input text missing parenthesis? Can you act on its source? If no, precise then exactly what is desired. – PJProudhon Feb 20 '18 at 14:22
  • @PJProudhon the input is the code typed by hand. It is sort of the compiler (like CoffeeScript). But in this task we are dealing not in all of its functionality, but only a part of it - putting parentheses in the right plases – Mee Feb 20 '18 at 14:26
  • Ok. In your particular sample, you could use `^(\s*[^\s]*)\s*(.*)$` with `$1($2)` as replacement ([demo](https://regex101.com/r/AFY3hd/1)). But it won't work as it looks intended if any statement like `myVar = someValue`. – PJProudhon Feb 20 '18 at 14:30
  • @PJProudhon well, this (your comment solution) has a very limited functionality, that can be applied only to the provided example, but what is needed is the functionality, that I have already created + what is desired (not allowing parentheses to wrap an odd amount of quotation marks). – Mee Feb 20 '18 at 14:33
  • This is exactly the complexity I'm trying to point out. How do you consider your starting and ending quotation? What should you do when there's an odd amount of it? – PJProudhon Feb 20 '18 at 14:54
  • @PJProudhon You say, it is not possible and that I will not be able to do it?? Well, I have just figured it out! I will answer my own question. Thank you for your time. You can check out the answer, if you want, in a few minutes. – Mee Feb 20 '18 at 15:03

2 Answers2

1

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.

Mee
  • 99
  • 9
  • See that you've come up with an answer *somewhat* similar to mine. You don't check for quote types in strings though. This solution will accept a string like `"A bunch of words'`. Is that intentional? It wont work with `"A single quote (') inside a double quoted string either"`. – SamWhan Feb 20 '18 at 15:28
  • @PJProudhon well, I have made a little mistake. I have edited my answer and you can check it again. Works like a charm :) – Mee Feb 20 '18 at 15:42
  • @ClasG Well, things like `"A bunch of words'` dont seem to bother much. But `"A single quote (') inside a double quoted string either"` actually works – Mee Feb 20 '18 at 15:49
  • @PJProudhon Thanks, I appreciate it :) – Mee Feb 20 '18 at 15:50
0

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 ;)

SamWhan
  • 8,296
  • 1
  • 18
  • 45
  • And with a `myVar = myValue` statement? – PJProudhon Feb 20 '18 at 15:36
  • @ClasG Thank you for your answer, but I didnt want to lose the functionality, that I have already created. The problem with your solution, is that, it wont work on statements such as `else if`, and other of this kind. As you have written, it takes the initial "command" and then does the processing, but that would cause incorrect behaviour in different other scenarious. – Mee Feb 20 '18 at 15:46