For the regex gurus, split by -> and avoiding bracket/quotes contents - javascript

Given string:
funny -> A_gre$" [ "at -> looks -> great/*54[ [funny " -> [ " -> [great -> yolo] -> looks]][great] -> a2afg34423*/- -> yolo" -> [ "
Split to Array:
funny
A_gre$' [ 'at
looks
great/*54[ [funny ' -> [ ' -> [great -> yolo] -> looks]][great]
a2afg34423*/-
yolo' -> [ '
A Regex Solution??!?
Basically, if there are quotes around the bracket(s), avoid the brackets' function as open/close delimiters otherwise make sure the text between the open bracket and close bracket are voided. How would i achieve this using Regex?
My Parser Solution Test
var s = "funny -> A_gre$' [ 'at -> looks -> great/\*54[ [funny ' -> [ ' ->"
+ "[great -> yolo] -> looks]][great] -> a2afg34423*/- -> yolo' -> [ '",
p = 0,
z = [0],
q = 0,
x = s.split('');
//Looking for \" not \'
for(var i = 0; i< x.length; i++){
var b = x[i],
c = x[i + 1],
q = b == "'" ? ++q : q,
p = !(q % 2) ? b == '[' ? ++p : b == ']' ? --p : p : p;
if(b == '-' && c == '>' && !p && !(q % 2))
z.push(i + 2);
if(i == x.length - 1){
z.push(x.length); x = [];
for(var u = 0; u < z.length; u++)
z[u + 1] !== undefined ?
x.push(s.substring(z[u], z[u + 2] !== undefined ?
z[u + 1]-2 : z[u + 1]).trim()) : 0;
}
}
console.log(x)
Ouput:
->>> [
"funny",
"A_gre$' [ 'at",
"looks",
"great/*54[ [funny ' -> [ ' -> [great -> yolo] -> looks]][great]",
"a2afg34423*/-",
"yolo' -> [ '"
]

Try this pattern:
([^\s\[\"]*\[[^\]]+\])\S*|([^\s\[\"]*\"[^\"]+\")\S*|(\w\S*)
Use regexpal to see what it matches. It consists of three parts. The description for one of them is as follows:
([^\s\[\"]*\[[^\]]+\])\S*
expressions that reads non-space, non-quote, and non-bracket characters, until it reaches an open bracket, then reads the bracket contents until it reaches the closing bracket, then reads any non-space characters occurring after it. This is more detailed description of bracket matching part:
\[ : opening bracket character
[ : regex syntax for starting a set definition
^ : It's a negative set, i.e., set of characters which are NOT:
\] : closing bracket character
]+ : regex syntax for ending a set definition and the + operator for matching 1 or more occurrences
\] : closing bracket character
Another section handles the quotes, and another section matches words without bracket and quotes.
The following code shows how to see the matches, and how to extract them:
var input = 'funny -> A_gre$" [ "at -> looks -> great/54[ [funny " -> [ " -> [great -> yolo] -> looks]][great] -> a2afg34423/- -> yolo" -> [ "'
var regexp = /([^\s\[\"]*\[[^\]]+\])\S*|([^\s\[\"]*\"[^\"]+\")\S*|(\w\S*)/g;
var result = input.match(regexp)
console.log("Array of matches are:");
console.log(result);
var results = regexp.exec(input);
while(results != null) {
console.log("index: " + results.index + " found: " + results[0]);
results = regexp.exec(input);
}
This can be seen live here: http://jsfiddle.net/LXqch/1/

Related

Regex test is getting failed in nodejs?

I have two sentences which I need to compare and produce the result. The sentences are listed below.
var msg = "Hi this is LT ~ ! # # $ % ^ & * ( ) _ - + = { [ } ] | \\ : ; \" ' < , > . ? / End {#val#}"
var msg2 = "Hi this is LT ~ ! # # $ % ^ & * ( ) _ - + = { [ } ] | \\ : ; \" ' < , > . ? / End 123"
Both the sentences are equal except for the val portion and it can be ignored. That's what below code is trying to do.
//Trying to add escape character for special characters
msg = msg.replace(/[-[\]{}()*+?.,\\^$|#]/g, '\\$&');
msg2 = msg2.replace(/[-[\]{}()*+?.,\\^$|#]/g, '\\$&');
//Adding space only if two {#val#} exists, else updating \\s* (can be many spaces or without spaces)
msg = msg.replace(/(^|.)\s($|.)/g, (x, g1, g2) => (x == "} {" ? x : g1 + "\\s\*" + g2));
//Replacing val with 1,29 (characters can be up to 29 in place of val)
var separators =/{#val#}|((\\s\*))/gi;
msg= msg.replace(separators, (x, y) => y ? y : ".(\\S{1,29})");
let regex = RegExp("^" + msg+ "$");
//Comparing two sentences
console.log(regex.test(msg2);
It is getting failed. I don't have issues with val and pace, but if i add special characters in the sentences it gives me failure result only.
At the end of the script, this is the value of msg:
Hi\s*this\s*is\s*DLT\s*test\s*~ !\s*# \#\s*\$\s*% \^\s*& \*\s*\(\s*\)\s* _\s*\-\s*\+\s*= \{\s*\[\s*\}\s*\]\s*\|\s*\\\s*: ;\s*" '\s*< \,\s*> \.\s*\?\s*/ End\s*\{\#val\#\}
And this is the value of msg2:
Hi this is DLT test ~ ! # \# \$ % \^ & \* \( \) _ \- \+ = \{ \[ \} \] \| \\ : ; " ' < \, > \. \? / End 123
The first is not a valid regular expression for the second, because
\{\#val\#\} does not match 123 (use instead: var separators =/\\{\\#val\\#\\}|((\\s\*))/gi;);
msg2 characters should not be escaped.
See a working example below:
var msg = "Hi this is LT ~ ! # # $ % ^ & * ( ) _ - + = { [ } ] | \\ : ; \" ' < , > . ? / End {#val#}"
var msg2 = "Hi this is LT ~ ! # # $ % ^ & * ( ) _ - + = { [ } ] | \\ : ; \" ' < , > . ? / End 123"
//Trying to add escape character for special characters
msg = msg.replace(/[-[\]{}()*+?.,\\^$|#]/g, '\\$&');
//Adding space only if two {#val#} exists, else updating \\s* (can be many spaces or without spaces)
msg = msg.replace(/(^|.)\s($|.)/g, (x, g1, g2) => (x == "} {" ? x : g1 + "\\s\*" + g2));
//Replacing val with 1,29 (characters can be upto 29 in place of val)
var separators =/\\{\\#val\\#\\}|((\\s\*))/gi;
msg = msg.replace(separators, (x, y) => y ? y : ".(\\S{1,29})");
let regex = RegExp("^" + msg+ "$");
//Comparing two sentences
console.log(regex.test(msg2)); //logs 'true'

CodeSignal reverseParentheses Failing one case

Write a function that reverses characters in (possibly nested) parentheses in the input string.
Input strings will always be well-formed with matching ()s.
For inputString = "(bar)", the output should be
reverseInParentheses(inputString) = "rab";
For inputString = "foo(bar)baz", the output should be
reverseInParentheses(inputString) = "foorabbaz";
For inputString = "foo(bar(baz))blim", the output should be
reverseInParentheses(inputString) = "foobazrabblim".
[input] string inputString
A string consisting of lowercase English letters and the characters ( and ). It is guaranteed that all parentheses in inputString form a regular bracket sequence.
Guaranteed constraints:
0 ≤ inputString.length ≤ 50.
[output] string
Return inputString, with all the characters that were in parentheses reversed.
My Solution
Java Script
function reverseInParentheses(inputString) {
let arr = inputString
let start = arr.indexOf(')') < arr.lastIndexOf('(') ? arr.indexOf('(') : arr.lastIndexOf('(')
let end = arr.indexOf(')')
let temp = arr.substring(start + 1, end)
if(start !== -1 && end !== -1){
return reverseInParentheses(arr.substring(0, start) +
[...temp].reverse().join('') +
arr.substring(end + 1))
}
return arr
}
Problem
I am passing all cases except for final hidden case, no runtime or execution time limit error is being returned. So I am having trouble figuring out what scenario is causing the fail. I really want to use my own solution instead of copying the regex ones and in my mind this solution should work, perhaps a more experienced mind can show my folly. Thanks in advance.
The problem is that your calculation of start and end really don't work. And there's no simple fix to this problem.
The comment from Jonas Wilms suggests trying '((see)(you))'. For this test case, you will get start and end like this:
0 5
((see)(you))
^ ^
start ----' '---- end
Note that the start and end are not an actual pair here. There's another '(' in between.
You can fix this up by doing a more sophisticated calculation of these values, by iterating through the characters, updating start every time you hit a '(' and updating end when you hit a ')', then stopping.
That might look like this:
function reverseInParentheses(inputString) {
let arr = inputString
let i = 0, start = 0, end = -1
while (end < start && i < arr.length) {
if (arr[i] == '(') {start = i}
if (arr[i] == ')') {end = i}
i++
}
let temp = arr.substring(start + 1, end)
if(start !== -1 && end !== -1){
return reverseInParentheses(arr.substring(0, start) +
[...temp].reverse().join('') +
arr.substring(end + 1))
}
return arr
}
console .log (reverseInParentheses('(bar)'))
console .log (reverseInParentheses('foo(bar)baz'))
console .log (reverseInParentheses('foo(bar(baz))blim'))
console .log (reverseInParentheses('((see)(you))'))
I don't particularly like this, combining the iteration to find the parentheses with recursion to keep reapplying the function until there are none left. It feels awkward.
There are other solutions, as you noted. One would be to use regular expressions. Note that the language of balanced parentheses is not a regular language, and hence cannot be captured by any one regular expression, but you can repeatedly apply regular expression operations in an iteration or a recursion to get this to work. Here is one version of that.
const rev = ([...cs]) => cs.reverse().join('')
const reverseInParentheses = (s) =>
/\(([^)]*)\)/ .test (s)
? reverseInParentheses (s .replace(/(.*)\(([^)]*)\)(.*)/, (_, a, b, c) => a + rev(b) + c))
: s
console .log (reverseInParentheses('(bar)'))
console .log (reverseInParentheses('foo(bar)baz'))
console .log (reverseInParentheses('foo(bar(baz))blim'))
console .log (reverseInParentheses('((see)(you))'))
Briefly, this finds innermost pairs of parentheses, replaces them with the reversal of their content, then recurs on the result, bottoming out when there are no more pairs found.
This solution was thrown together, and there are probably better regular expressions operations available.
But I actually prefer a different approach altogether, treating the characters of the string as events for a simple state machine, with a stack of nested parenthesized substrings. Here is what I wrote:
const reverseInParentheses = ([c, ...cs], res = ['']) =>
c == undefined
? res [0]
: c == '('
? reverseInParentheses (cs, [...res, ''])
: c == ')'
? reverseInParentheses (cs, [...res.slice(0, -2), res[res.length - 2] + [...res[res.length - 1]].reverse().join('')])
: reverseInParentheses (cs, [...res.slice(0, -1), res[res.length - 1] + c])
console .log (reverseInParentheses('(bar)'))
console .log (reverseInParentheses('foo(bar)baz'))
console .log (reverseInParentheses('foo(bar(baz))blim'))
console .log (reverseInParentheses('((see)(you))'))
We can examine the behavior by adding this as the first line of the body expression:
console .log (`c: ${c ? `"${c}"` : '< >'}, cs: "${cs.join('')}", res: ["${res.join('", "')}"]`) ||
For '((see)(you))', we would get something like this:
curr (c)
remaining (cs)
stack (res)
"("
"(see)(you))"
[""]
"("
"see)(you))"
["", ""]
"s"
"ee)(you))"
["", "", ""]
"e"
"e)(you))"
["", "", "s"]
"e"
")(you))"
["", "", "se"]
")"
"(you))"
["", "", "see"]
"("
"you))"
["", "ees"]
"y"
"ou))"
["", "ees", ""]
"o"
"u))"
["", "ees", "y"]
"u"
"))"
["", "ees", "yo"]
")"
")"
["", "ees", "you"]
")"
""
["", "eesuoy"]
< >
< >
["yousee"]
I choose to process this state machine recursively, because I prefer working with immutable data, not reassigning variables, etc. But this technique should work equally well with an iterative approach.
String reverseInParentheses(String inputString) {
//recursion
int start = -1;
int end = -1 ;
for(int i = 0; i < inputString.length(); i++){
if(inputString.charAt(i) == '('){
start = i;
}
if(inputString.charAt(i) == ')'){
end = i;
String reverse = new StringBuilder(inputString.substring(start+1, end)).reverse().toString();
return reverseInParentheses(inputString.substring(0, start) + reverse+ inputString.substring(end+1));
}
}
return inputString;
}
function solution(inputString) {
let s;
let e = 0;
while (e < inputString.length) {
//if we saw a ')', we mark the index as e, then we go back the
//nearest '(', and mark the index as s
if (inputString[e] === ')') {
s = e;
while (inputString[s] !== '(') {
s--;
}
//get the string in the parenthesis
let beforeRevert = inputString.slice(s + 1, e);
//revert it
let reversed = beforeRevert.split('').reverse().join('');
//put pieces together to get a new inputString
inputString = inputString.slice(0, s) + reversed +
inputString.slice(e + 1, inputString.length)
//because we get rid of the '(' and ')', now we are at index e-1 of
//new inputString
e--;
} else {
e++;
}
}
return inputString;
}
You could try this. It worked for me.
function solution(s) {
while (true) {
let c = s.indexOf(")");
if (c === -1) {
break;
}
let o = s.substring(0, c).lastIndexOf("(");
let start = s.substring(0, o);
let middle = s.substring(o + 1, c).split("").reverse().join("");
let end = s.substring(c + 1, s.length);
s = start + middle + end;
}
return s;
}

Regex to match string with contains closed brackets

I need to create regex rule to match string with doesnt' contain ( ) character and also strings that have them inside but always closed (but not nested. Another thing that empty () is also wrong
Good strings (should be matched):
aaaaaa
(asdasd)
aaaa(bbb)a
(aaa)aaaa
aaaaaa(aaaa)
aaaa(bbb)(ccc)ddd
aaaa(bbbb)cccc(dddd)eeee
Bad strings (there shouldn't be match):
)aaaa
)aaaa(asd)
aaaaaa(
aaaa(bbb))
aaa(bbb
aaaaa((bbbb)cccc
aaaa(bbbb))ccc
aaaa(aasd(adssad))ad
adassd(aas(add)adsa(asda)ad)
()
Tried and created something like this (?!.*[(]{2,})(?!.*[)]{2,})(?![)])(?!.*[(]$).*$ but still it isn't good. Any help with this?
You can use this regex for your job:
/^(?!$)(?:[^)(]*\([^()]+\))*[^)(]*$/gm
RegEx Demo
RegEx Breakup:
^ - Line start
(?!$) - Negative lookahead to make sure we don't match empty string
(?: - Start of a non-capturing group
[^)(]* - Match 0 or more of anything but ( and )
\( - Match a (
[^()]+ - Match 1 or more of anything but ( and )
\) - Match a literal )
)* - End of the non-capturing group, * makes it match 0 or more times
[^)(]*- Match 0 or more of anything but ( and )
$ - Line end
If you want to check for balanced parens, you can use a function like this:
function balanced(str) {
var a = 0;
for(var i = 0; i < str.length; i++) { // for each character in str
if(str.charAt(i) == '(') a++; // if it's an open paren, increment a
else if(str.charAt(i) == ')') a--; // if it's a close one, decrement a
}
return a == 0; // if a == 0 then it's balanced (true), if not then it's not balanced (false)
}
var s1 = "aaaa(bbbb)cccc(dddd)eeee";
var s2 = "aaaa(bbbb(cccc(dddd)eeee";
var s3 = "aaaa";
console.log(s1 + " => " + balanced(s1));
console.log(s2 + " => " + balanced(s2));
console.log(s3 + " => " + balanced(s3));
Or if you insist on using regexp, then use two regexp to check for balanced parens like this:
function balanced(str) {
var opened = str.match(/\(/g); // match open parens
var closed = str.match(/\)/g); // match close parens
opened = opened? opened.length: 0; // get the count of opened parens, if nothing is matched then 0
closed = closed? closed.length: 0; // get the count of closed parens, if nothing is matched then 0
return opened == closed; // balanced means the count of both is equal
}
var s1 = "aaaa(bbbb)cccc(dddd)eeee";
var s2 = "aaaa(bbbb(cccc(dddd)eeee";
var s3 = "aaaa";
console.log(s1 + " => " + balanced(s1));
console.log(s2 + " => " + balanced(s2));
console.log(s3 + " => " + balanced(s3));
This should do the trick:
^([^()]|\([^()]+\))+$
reads "match not a paren or ( no parens here ), once or more, whole string"
If you want to match balanced parens at any level, a single expression is not possible in js, due to lack of recursion support, but a function will be rather trivial.
let balanced = function(s) {
var re = /\([^()]*\)/g
while (s.match(re)) s = s.replace(re, '')
return !s.match(/[()]/)
}
console.log(balanced('a(b((d))e) (f) g'))
console.log(balanced('a(b((d))e? (f) g'))
or without regexes:
let balanced = s => {
let c = 0;
for (let x of s) {
if (x == '(') c++;
if (x == ')' && !c--) return false;
}
return !c;
};

Design a regular expression for a sentence and its subset

For the following two sentences,
var first_sentence = 'My cat is sleeping';
var second_sentence = 'My cat is sleeping with a blanket';
I have tried to use the following regexp to get both verb (sleeping) and the noun (a blanket).
var regex = /My cat is (.+?)\s+with.?(.+)?/gi.exec('My cat is sleeping with a blanket');
console.log(regex);
/*
[ 0 : 'My cat is sleeping with a blanket'
1 : 'sleeping'
2 : 'a blanket'
index : 0
input : 'My cat is sleeping with a blanket'
length : 3 ]
*/
This regular expression got it well but when I apply it to the first sentence, it returns null, any idea about that ?
var regex = /My cat is (.+?)\s+with.?(.+)?/gi.exec('My cat is sleeping');
console.log(regex);
// null
In the first sentence, there is no \s+with.?(.+)? part that requires some text to be present (1+ whitespaces and then with). You need to wrap the part of the pattern that is optional with (?:....)?:
/My cat is (\S+)(?:\s+with\s+(.*))?/gi
See the regex demo
Details:
My cat is - a literal text
(\S+) - Group 1 capturing 1+ non-whitespace symbols
(?:\s+with\s+(.*))? - an optional sequence of:
\s+with\s+ - with word enclosed with 1+ whitespaces on both sides
(.*) - Group 2 capturing any 0+ chars other than line break symbols
JS:
var ss = [ "My cat is sleeping", "My cat is sleeping with a blanket"];
var rx = /My cat is (\S+)(?:\s+with\s+(.*))?/i;
for (var s = 0; s < ss.length; s++) {
document.body.innerHTML += "Testing \"<i>" + ss[s] + "</i>\"... ";
if ((m = ss[s].match(rx))!==null) {
document.body.innerHTML += "Found: <b>" + m[1] + "</b>" + (m[2] ? " and <b>" + m[2] : "") + "</b><br/>";
} else {
document.body.innerHTML += "NOT Matched: <b>" + ss[s] + "</b><br/>";
}
}

JavaScript substr(), Get Characters in the Middle of the String

I have a string, var str = "Runner, The (1999)";
Using substr(), I need to see if ", The" is contained in str starting from 7 characters back, then if it is, remove those characters and put them in the start. Something like this:
if (str.substr(-7) === ', The') // If str has ', The' starting from 7 characters back...
{
str = 'The ' + str.substr(-7, 5); // Add 'The ' to the start of str and remove it from middle.
}
The resulting str should equal "The Runner (1999)"
Please, no regular expressions or other functions. I'm trying to learn how to use substr.
Here you go, using only substr as requested:
var str = "Runner, The (1999)";
if(str.substr(-12, 5) === ', The') {
str = 'The ' + str.substr(0, str.length - 12) + str.substr(-7);
}
alert(str);
Working JSFiddle
It should be noted that this is not the best way to achieve what you want (especially using hardcoded values like -7 – almost never as good as using things like lastIndexOf, regex, etc). But you wanted substr, so there it is.
var str = "Runner, The (1999)";
if(str.indexOf(", The") != -1) {
str = "The "+str.replace(", The","");
}
If you want to use just substr:
var a = "Runner, The (1999)"
var newStr;
if (str.substr(-7) === ', The')
newStr= 'The ' +a.substr(0,a.length-a.indexOf('The')-4) + a.substr(a.indexOf('The')+3)
Use a.substr(0,a.length-a.indexOf('The')-4) to obtain the words before "The" and a.substr(a.indexOf('The')+3) to obtain the words after it.
So, you say that the solution should be limited to only substr method.
There will be different solutions depending on what you mean by:
", The" is contained in str starting from 7 characters back
If you mean that it's found exactly in -7 position, then the code could look like this (I replaced -7 with -12, so that the code returned true):
function one() {
var a = "Runner, The (1999)";
var b = ", The";
var c = a.substr(-12, b.length);
if (c == b) {
a = "The " + a.substr(0, a.length - 12) +
a.substr(a.length - 12 + b.length);
}
}
If, however, substring ", The" can be found anywhere between position -7 and the end of the string, and you really need to use only substr, then check this out:
function two() {
var a = "Runner, The (1999)";
var b = ", The";
for (var i = a.length - 12; i < a.length - b.length; i++) {
if (a.substr(i, b.length) == b) {
a = "The " + a.substr(0, i) + a.substr(i + b.length);
break;
}
}
}

Categories