Using javascript, im trying to make a node.js module to parse predicate logic statements.
I've been working on this regex for a bit and I just can't get it to behave the way i want
1. /\(((?:[^{}]*\([^{}]*\))*[^{}]*?)\)/
2. .replace(/\)((?:[^{}]*\)[^{}]*\))*[^{}]*?)\(/,'):::(')
the latter works fine on things like (a&s&d&a&s&d)->(a&s&(d)&s|(d)) but i just switched the delimiters...
what I'm trying to do is change a statement like
((r|a)&(s|r))&(~r)->(r|(q&r))->q
into
1->2->q
I can certainly write a procedural function to do it, that would be a fine solution. But Im really stuck on this.
The only real specification is the regex needs to respect the outermost parenthesis the most, and be able to replace separate ones.
Because this is not regex friendly I put togethor a couple of functions that do what you are looking for. The first matches parenthesis with depth:
function match_parens(code_to_test, level, opening, closing){
var sub_match, matched;
return code_to_test.replace(new RegExp('^([^'+opening+closing+']*(.))[\\s\\S]*$'), function(full_match, matched, $2, offset, original){
if ($2 == opening){
sub_match = match_parens(original.substr(offset+matched.length), level + 1, opening, closing);
matched = matched + sub_match
}
else if (level > 1){
sub_match = match_parens(original.substr(offset+matched.length), level - 1, opening, closing);
matched += sub_match;
}
return matched;
});
}
This function takes a string and returns everything up until the closing element.
The next function helps pulls a string passed to it apart, replacing all content in parenthesis with escalating numbers:
function pull_apart(testString){
var count = 1,
returnString = '',
tempIndex = testString.indexOf('(');
while (tempIndex !== -1){
returnString += testString.substring(0,tempIndex)+count;
count += 1;
testString = testString.substring(testString.indexOf('(') + match_parens(testString.substr(tempIndex + 1), 1, '(', ')').length+1)
tempIndex = testString.indexOf('(');
}
returnString += testString;
return returnString;
}
Running pull_apart('((r|a)&(s|r))&(~r)->(r|(q&r))->q') returns "1&2->3->q", which is what you are looking for. While this is not entirely regex, it is utilized in the paren matching function up above. I'm not sure if this fits whatever use case you had in mind, but hopefully it helps.
Related
I'm trying to get better at javascript through codewars.com katas, and I came across an exercice in which things like element[i]=element[i].toLowerCase() doesn't change anything at all.
I would like to have some help with my code, here is the exercice's instructions followed by my code:
(Please note that I'm not very experienced with JS so the code may not be perfect at all)
A string is considered to be in title case if each word in the string
is either:
(a) capitalised (that is, only the first letter of the word
is in upper case) or
(b) considered to be an exception and put entirely into lower case unless it is the first word, which is always capitalised.
Write a function that will convert a string into title case, given an optional list of exceptions (minor words). The list of minor words will be given as a string with each word separated by a space.
Your function should ignore the case of the minor words string -- it should behave in the same way even if the case of the minor word string is changed.
Arguments:
First argument (required): the original string to be converted.
Second argument (optional): space-delimited list of minor words that must always be lowercase except for the first word in the string. The JavaScript/CoffeeScript tests will pass undefined when this argument is unused.
function titleCase(title, minorWords) {
if(title.length==0){return ""}
var titlesplit = title.split(" ")
if(minorWords){
minorWords=minorWords.split(" ")
}
var solutionstring = ""
titlesplit.forEach(element => myfunction(element,minorWords))
solutionstring[0] = solutionstring[0].toUpperCase()
return solutionstring
function myfunction(element,minorWords){
var elementlength= element.length
var i=0
if(minorWords && minorWords.includes(element)){
for(i;i<elementlength;i++){
element[i]=element[i].toLowerCase()
}
}else {
for(i;i<elementlength;i++){
if(i==0){element[i]=element[i].toUpperCase()}
else{element[i]=element[i].toLowerCase()}
}
}
if(solutionstring.length==0){solutionstring=solutionstring+element}else{solutionstring=solutionstring+" "+element}
return
}
}
As pointed out in comments, Strings are immutable in JavaScript.
Additionally, for searching use Maps instead of includes.
Likewise you can see what Set in JavaScript is and easily use Set here.
Added comments for you better understanding.
function titleCase(title, minorWords) {
// Use === for comparison
// Prefer using curly braces even for single statements
if (title.length === 0) {
return "";
}
var titlesplit = title.split(" ");
// Maps/Objects give O(1) search compared to arrays O(n)
// Key,value pairs - similar to dictionary
var minorWordsMap = {};
minorWords.split(" ").forEach(i => minorWordsMap[i.toLowerCase()] = true);
var finalWords = titlesplit.map((element, index) => convertCase(element, index));
finalWords[0] = toPascalCase(finalWords[0]);
return finalWords.join(" ");
function toPascalCase(s) {
s = s.split("");
s[0] = s[0].toUpperCase();
return s.join("");
}
function convertCase(element, index) {
const lElement = element.toLowerCase();
// If element is part of exception words, ignore
if(index !== 0 && minorWordsMap[lElement]) {
return element;
}
// If first element or not in exception list, send Title case
return toPascalCase(lElement);
}
}
I am new in programing and right now I am working on one program. Program need to find the substring in a string and return the index where the chain starts to be the same. I know that for that I can use "indexOf". Is not so easy. I want to find out substrings with at moste one different char.
I was thinking about regular expresion... but not really know how to use it because I need to use regular expresion for every element of the string. Here some code wich propably will clarify what I want to do:
var A= "abbab";
var B= "ba";
var tb=[];
console.log(A.indexOf(B));
for (var i=0;i<B.length; i++){
var D=B.replace(B[i],"[a-z]");
tb.push(A.indexOf(D));
}
console.log(tb);
I know that the substring B and string A are the lowercase letters. Will be nice to get any advice how to make it using regular expresions. Thx
Simple Input:
A B
1) abbab ba
2) hello world
3) banana nan
Expected Output:
1) 1 2
2) No Match!
3) 0 2
While probably theoretically possible, I think it would very complicated to try this kind of search while attempting to incorporate all possible search query options in one long complex regular expression. I think a better approach is to use JavaScript to dynamically create various simpler options and then search with each separately.
The following code sequentially replaces each character in the initial query string with a regular expression wild card (i.e. a period, '.') and then searches the target string with that. For example, if the initial query string is 'nan', it will search with '.an', 'n.n' and 'na.'. It will only add the position of the hit to the list of hits if that position has not already been hit on a previous search. i.e. It ensures that the list of hits contains only unique values, even if multiple query variations found a hit at the same location. (This could be implemented even better with ES6 sets, but I couldn't get the Stack Overflow code snippet tool to cooperate with me while trying to use a set, even with the Babel option checked.) Finally, it sorts the hits in ascending order.
Update: The search algorithm has been updated/corrected. Originally, some hits were missed because the exec search for any query variation would only iterate as per the JavaScript default, i.e. after finding a match, it would start the next search at the next character after the end of the previous match, e.g. it would find 'aa' in 'aaaa' at positions 0 and 2. Now it starts the next search at the next character after the start of the previous match, e.g. it now finds 'aa' in 'aaaa' at positions 0, 1 and 2.
const findAllowingOneMismatch = (target, query) => {
const numLetters = query.length;
const queryVariations = [];
for (let variationNum = 0; variationNum < numLetters; variationNum += 1) {
queryVariations.push(query.slice(0, variationNum) + "." + query.slice(variationNum + 1));
};
let hits = [];
queryVariations.forEach(queryVariation => {
const re = new RegExp(queryVariation, "g");
let myArray;
while ((searchResult = re.exec(target)) !== null) {
re.lastIndex = searchResult.index + 1;
const hit = searchResult.index;
// console.log('found a hit with ' + queryVariation + ' at position ' + hit);
if (hits.indexOf(hit) === -1) {
hits.push(searchResult.index);
}
}
});
hits = hits.sort((a,b)=>(a-b));
console.log('Found "' + query + '" in "' + target + '" at positions:', JSON.stringify(hits));
};
[
['abbab', 'ba'],
['hello', 'world'],
['banana', 'nan'],
['abcde abcxe abxxe xbcde', 'abcd'],
['--xx-xxx--x----x-x-xxx--x--x-x-xx-', '----']
].forEach(pair => {findAllowingOneMismatch(pair[0], pair[1])});
I ran into a situation at work today where I needed to write the inverse of a function that I had already written, but I found it inefficient to write the inverse manually because it seems like I would be repeating a lot of my code, and if I were to update the original function I would have to update the inverse with the corresponding changes. The function I am talking about looks something like this:
var f = function(id, str) {
if (id === 0) {
return str.substring(0, 4) + " " + str.substring(4, 8);
} else if (id === 1) {
return str.substring(0, 3) + "/" + str.substring(3, 8);
} else if (id === 2) {
return str.substring(0, 4) + "-" + str.substring(4, 8);
} else if (id == 3) {
return str.substring(0, 3) + "," + str.substring(3, 8);
}
}
So for example f(0, "ABCDEFGH") will return "ABCD EFGH". I need an inverse function that uses the function f(id, str) to come up with inputs from the output. So finverse(formattedStr) should return a dictionary of the corresponding inputs. For example, finverse("ABCD EFGH") should return { id: 0, str: "ABCDEFGH" }. Would it be possible to make use of the existing function f to write this inverse such that even if I were to update the original function with an extra "else if" clause, I wouldn't have to update finverse. In other words I do not want to manually construct finverse with if statements to map the outputs back to the inputs, rather I want to manipulate the original function somehow to come up with an inverse. Is this possible in javascript?
with a slight re-factoring, the task is actually pretty simple. You don't need all those ifs, and actually, ifs run slower than Object property lookup, not to mention them not being sealed-up in a private function somewhere...
we can accomplish a translation ( 1 in, 1+ out) without any flow logic:
// replace all the IF logic with an externally-modifiable logic table:
f.lut=[ [4," "], [3,"/"], [4,"-"], [3,","] ]; //(id=index, 0=pos, 1=char)
// simplify f() using the table to make choices instead of conditionals:
function f(id, str) {
id = f.lut[id];
return str.substring(0, id[0]) + id[1] + str.substring(id[0], 8);
}
// use the same table in reverse to compose an inverse function:
function finverse(s){
return {
id: +f.lut.map(function(A,i){ return A[1]==s.split(/[\w]+/).filter(Boolean)[0] ?
String(i):
""
}).filter(Boolean)[0][0],
str: s.split(/[\W]+/).filter(Boolean).join('')
};
}
// first, test new version of f():
f(0, "ABCDEFGH") // ABCD EFGH
f(1, "ABCDEFGH") // ABC/DEFGH
f(2, "ABCDEFGH") // ABCD-EFGH
f(3, "ABCDEFGH") // ABC,DEFGH
// now, test the inverse:
finverse("ABCD EFGH") //{id:0, str:"ABCDEFGH"}
finverse("ABC/DEFGH") //{id:1, str:"ABCDEFGH"}
finverse("ABCD-EFGH") //{id:2, str:"ABCDEFGH"}
finverse("ABC,DEFGH") //{id:3, str:"ABCDEFGH"}
let us know if this isn't what you were wanting, i wasn't 100% sure...
There is really no way to make it work perfectly. That is impossible to implement with nice speed characteristic. So, I try to give you two ways of solving this problem:
Make global object named fRules with rules which used in f().
fRules = [
{
id: 0,
char: ' ',
insertPosition: 4
},
// ... other rules ...
];
Then you can use fRules in f() simply finding rule with needed id and in fInverse iterating over array of rules and finding good one. Now you don't need to change f(), only fRules();
f.toString() to get text of function and parse function to abstract syntax tree with something. Like inner functions of UglifyJs. Read more here. Then you must manually write some inverser based on your function syntax tree. Ugly idea
An example of what im trying to get:
String1 - 'string.co.uk' - would return 'string' and 'co.uk'
String2 - 'random.words.string.co.uk' - would return 'string` and 'co.uk'
I currently have this:
var split= [];
var tld_part = domain_name.split(".");
var sld_parts = domain_name.split(".")[0];
tld_part = tld_part.slice(1, tld_part.length);
split.push(sld_parts);
split.push(tld_part.join("."));
With my current code, it takes the split parameter from the beginning, i want to reverse it if possible. With my current code it does this:
String1 - 'string.co.uk' - returns 'string' and 'co.uk'
String2 - 'random.words.string.co.uk' - would return 'random` and 'words.string.co.uk'
Any suggestions?
To expand upon elclanrs comment:
function getParts(str) {
var temp = str.split('.').slice(-3) // grabs the last 3 elements
return {
tld_parts : [temp[1],temp[2]].join("."),
sld_parts : temp[0]
}
}
getParts("foo.bar.baz.co.uk") would return { tld_parts : "co.uk", sld_parts : "baz" }
and
getParts("i.got.99.terms.but.a.bit.aint.one.co.uk") would return { tld_parts : "co.uk", sld_parts : "one" }
try this
var str='string.co.uk'//or 'random.words.string.co.uk'
var part = str.split('.');
var result = part[part.length - 1].toString() + '.' + part[part.length - 1].toString();
alert(result);
One way that comes to mind is the following
var tld_part = domain_name.split(".");
var name = tld_part[tld_part.length - 2];
var tld = tld_part[tld_part.length - 1] +"."+ tld_part[tld_part.length];
Depending on your use case, peforming direct splits might not be a good idea — for example, how would the above code handle .com or even just localhost? In this respect I would go down the RegExp route:
function stripSubdomains( str ){
var regs; return (regs = /([^.]+)(\.co)?(\.[^.]+)$/i.exec( str ))
? regs[1] + (regs[2]||'') + regs[3]
: str
;
};
Before the Regular Expression Police attack reprimand me for not being specific enough, a disclaimer:
The above can be tightened as a check against domain names by rather than checking for ^., to check for the specific characters allowed in a domain at that point. However, my own personal perspective on matters like these is to be more open at the point of capture, and be tougher from a filtering point at a later date... This allows you to keep an eye on what people might be trying, because you can never be 100% certain your validation isn't blocking valid requests — unless you have an army of user testers at your disposal. At the end of the day, it all depends on where this code is being used, so the above is an illustrated example only.
How would it be a nice way of handling this?
I already thought on removing the comma and then parsing to float.
Do you know a better/cleaner way?
Thanks
parseFloat( theString.replace(/,/g,'') );
I don't know why no one has suggested this expression-
parseFloat( theString.replace(/[^\d\.]/g,'') );
Removes any non-numeric characters except for periods. You don't need custom functions/loops for this either, that's just overkill.
Nope. Remove the comma.
You can use the string replace method, but not in a one liner as a regexp allows.
while(str.indexOf(',')!=-1)str= str.replace(',','');
parseFloat(str);
Or to make a single expression without a regexp=
return parseFloat(str.split(',').join(''));
I'd use the regexp.
I don't have enough reputation to add a comment, but for anyone wondering on the performance for regex vs split/join, here's a quick fiddle: https://jsfiddle.net/uh3mmgru/
var test = "1,123,214.19";
var t0 = performance.now();
for (var i = 0; i < 1000000; i++)
{
var a = parseFloat(test.replace(/,/g,''));
}
var t1 = performance.now();
document.write('Regex took: ' + (t1 - t0) + ' ms');
document.write('<br>')
var t0 = performance.now();
for (var i = 0; i < 1000000; i++)
{
var b = parseFloat(test.split(',').join(''));
}
var t1 = performance.now();
document.write('Split/join took: ' + (t1 - t0) + ' ms');
The results I get are (for 1 million loops each):
Regex: 263.335 ms
Split/join: 1035.875 ms
So I think its safe to say that regex is the way to go in this scenario
Building on the idea from #kennebec, if you want to make sure that the commas are correct, and you don't want to replace commas, you could try something like this:
function myParse(num) {
var n2 = num.split(",")
out = 0
for(var i = 0; i < n2.length; i++) {
out *= 1000;
out += parseFloat(n2[i])
}
return out
}
alert(myParse("1,432,85"));
// Returns 1432085, as the comma is misplaced.
It may not be as fast, but you wanted alternatives :)
What about a simple function to solve most of the common problems?
function getValue(obj) {
Value = parseFloat( $(obj).val().replace(/,/g,'') ).toFixed(2);
return +Value;
}
The above function gets values from fields (using jQuery) assuming the entered values are numeric (I rather validate fields while user is entering data, so I know for sure field content is numeric).
In case of floating point values, if well formatted in the field, the function will return a float point value correctly.
This function is far from complete, but it quickly fix the "," (comma) issue for values entered as 1,234.56 or 1,234,567. It will return valid number as far the content is numeric.
The + (plus) sign in front of the variable Value in the return command is a "dirty trick" used in JavaScript to assure the variable content returned will be numeric.
it is easy to modify the function to other purposes, such as (for instance), convert strings to numeric values taking care of the "," (comma) issue:
function parseValue(str) {
Value = parseFloat( str.replace(/,/g,'') ).toFixed(2);
return +Value;
}
Both operations can even be combined in one function. I.e.:
function parseNumber(item,isField=false) {
Value = (isField) ? parseFloat( $(item).val().replace(/,/g,'') ).toFixed(2) : parseFloat( item.replace(/,/g,'') ).toFixed(2)
return +Value;
}
In such case, if function is called result = parseNumber('12,092.98'); it will parse the value as it is a String. But if called as result = parseNumber('#MyField', true); it will try to obtain the value from '#MyField'.
As I said before, such functions are far from complete, and can be expanded in many ways. One idea is to check the first character of the given parameter (string) and decide based on the string format where to obtain the value to be parsed (if 1st character is = '#' then it is an ID from a DOM object, otherwise, if it begins with a number, it must be a string to be parsed).
Try it... Happy coding.