Writing an inverse function in javascript? - javascript

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

Related

Where and why would you use tagged template literals? [duplicate]

I understand the syntax of ES6 tagged templates. What I don't see is the practical usability. When is it better than passing an object parameter, like the settings in jQuery's AJAX? $.ajax('url', { /*this guy here*/ })
Right now I only see the tricky syntax but I don't see why I would need/use it. I also found that the TypeScript team chose to implement it (in 1.5) before other important features. What is the concept behind tagged string templates?
You can use tagged templates to build APIs that are more expressive than regular function calls.
For example, I'm working on a proof-of-concept library for SQL queries on JS arrays:
let admins = sql`SELECT name, id FROM ${users}
WHERE ${user => user.roles.indexOf('admin') >= 0}`
Notice it has nothing to do with String interpolation; it uses tagged templates for readability. It would be hard to construct something that reads as intuitively with plain function calls - I guess you'd have something like this:
let admins = sql("SELECT name, id FROM $users WHERE $filter",
{ $users: users, $filter: (user) => user.roles.contains('admin') })
This example is just a fun side project, but I think it shows some of the benefits of tagged templates.
Another example, maybe more obvious, is i18n - a tagged template could insert locale-sensitive versions of your input.
See Sitepoint's explanation:
The final stage of template strings specification is about adding a custom function before the string itself to create a tagged template string.
...
For instance, here is a piece of code to block strings that try to inject custom DOM elements:
var items = [];
items.push("banana");
items.push("tomato");
items.push("light saber");
var total = "Trying to hijack your site <BR>";
var myTagFunction = function (strings,...values) {
var output = "";
for (var index = 0; index < values.length; index++) {
var valueString = values[index].toString();
if (valueString.indexOf(">") !== -1) {
// Far more complex tests can be implemented here :)
return "String analyzed and refused!";
}
output += strings[index] + values[index];
}
output += strings[index]
return output;
}
result.innerHTML = myTagFunction `You have ${items.length} item(s) in your basket for a total of $${total}`;
Tagged template strings can used for a lot of things like security, localization, creating your own domain specific language, etc.
They're useful because the function can (almost) completely define the meaning of the text inside it (almost = other than placeholders). I like to use the example of Steven Levithan's XRegExp library. It's awkward to use regular expressions defined as strings, because you have to double-escape things: Once for the string literal, and once for regex. This is one of the reasons we have regular expression literals in JavaScript.
For instance, suppose I'm doing maintenance on a site and I find this:
var isSingleUnicodeWord = /^\w+$/;
...which is meant to check if a string contains only "letters." Two problems: A) There are thousands of "word" characters across the realm of human language that \w doesn't recognize, because its definition is English-centric; and B) It includes _, which many (including the Unicode consortium) would argue is not a "letter."
Suppose in my work I've introduced XRegExp to the codebase. Since I know it supports \pL (\p for Unicode categories, and L for "letter"), I might quickly swap this in:
var isSingleUnicodeWord = XRegExp("^\pL+$"); // WRONG
Then I wonder why it didn't work, *facepalm*, and go back and escape that backslash, since it's being consumed by the string literal:
var isSingleUnicodeWord = XRegExp("^\\pL+$");
// ---------------------------------^
What a pain. Suppose I could write the actual regular expression without worrying about double-escaping?
I can: With a tagged template function. I can put this in my standard lib:
function xrex(strings, ...values) {
const raw = strings.raw;
let result = "";
for (let i = 0; i < raw.length; ++i) {
result += raw[i];
if (i < values.length) { // `values` always has one fewer entry
result += values[i];
}
}
return XRegExp(result);
}
Or alternately, this is a valid use case for reduce, and we can use destructuring in the argument list:
function xrex({raw}, ...values) {
return XRegExp(
raw.reduce(
(acc, str, index) => acc + str + (index < values.length ? values[index] : ""),
""
)
);
}
And then I can happily write:
const isSingleUnicodeWord = xrex`^\pL+$`;
Example:
// My tag function (defined once, then reused)
function xrex({raw}, ...values) {
const result = raw.reduce(
(acc, str, index) => acc + str + (index < values.length ? values[index] : ""),
""
);
console.log("Creating with:", result);
return XRegExp(result);
}
// Using it, with a couple of substitutions to prove to myself they work
let category = "L"; // L: Letter
let maybeEol = "$";
let isSingleUnicodeWord = xrex`^\p${category}+${maybeEol}`;
function test(str) {
console.log(str + ": " + isSingleUnicodeWord.test(str));
}
test("Русский"); // true
test("日本語"); // true
test("العربية"); // true
test("foo bar"); // false
test("$£"); // false
<script src="https://cdnjs.cloudflare.com/ajax/libs/xregexp/3.2.0/xregexp-all.min.js"></script>
The only thing I have to remember now is that ${...} is special because it's a placeholder. In this specific case, it's not a problem, I'm unlikely to want to apply a quantifier to the end-of-input assertion, but that's a coincidence...

How can I split a string containing multiple js statements into an array of strings each string containing one statement?

I have a string containing a number of JavaScript statements separated by ";".
I need to split this into an array of strings with each string containing an individual command.
I cannot simply use the string splitting function with ";" as the delimiter because ";" also exist in the other commands within strings.
How can I split a string containig multiple js statements into an array of strings each string containing an individual command?
For example I can have something like:
$('_32123').innerHTML="<div style=\"font-size:11px;margin-right:15px;margin-
bottom:5px;text-align:right;\" id=\"_134607\" noprint='no' noprintoverflow='no'>
</div>";document.onkeydown = function(event) { if (event.ctrlKey &&
event.keyCode == 89) Event(3160,'Refresh',{ q:'' }); };
Is there a library or something that can provide this functionality or how else can I solve this problem?
A regular expression will be too simple to split the JavaScript code into statements. This could be made working though for simple things, but there's JavaScript strings, JavaScript regexes and comments which make this more complex. Additionally, JavaScript constructs are not necessarily ending with semicolons. Consider this:
if (foo) { throw "bar"; }
Though throw "bar"; ends with semicolon, it is unclear whether you want to capture the whole if statement with its body or just the throw parts.
Apart from that, JavaScript statements may also end at a newline. The following are two valid JavaScript statements, though not separated by semicolons:
a = 1
b = 2
In order to deal with all these complex rules, you will need a language-aware parser. There are several JavaScript-parsing frameworks out there, and you have to choose a parser framework that suits you.
Following is an example for tokenizing the statements with Acorn. I ran the following code in nodejs after installing acorn with npm install acorn:
var code = "$('_32123').innerHTML=\"<div style=\\\"font-size:11px;margin-right:15px;margin-bottom:5px;text-align:right;\\\" id=\\\"_134607\\\" noprint='no' noprintoverflow='no'></div>\";document.onkeydown = function(event) { if (event.ctrlKey && event.keyCode == 89) Event(3160,'Refresh',{ q:'' }); };";
var acorn = require("acorn");
var tokens = acorn.parse(code);
tokens.body.forEach(function(token) {
console.log("statement: ", code.substr(token.start, token.end - token.start));
});
This will print the two top-level statements in the example code.
Note that the example JavaScript code you supplied has only two top-level statements (the two assignment expressions), but more than two statements in total. For example, there is also a function declaration and an if statement. These statements are sub-statements of the two top-level statements.
If you want to capture all these statements (top-level and sub-statements) in isolation, you will need to walk the abstract syntax tree generated by the parser and also recurse into subtokens. Going recursive is also necessary because JavaScript allows having nested structures (control structures, functions).
This will easily get a bit more complicated because you have to handle the different subtoken types. Here's an example implementation handling only a few types that demonstrates how the AST can be walked:
var code = "$('_32123').innerHTML=\"<div style=\\\"font-size:11px;margin-right:15px;margin-bottom:5px;text-align:right;\\\" id=\\\"_134607\\\" noprint='no' noprintoverflow='no'></div>\";document.onkeydown = function(event) { if (event.ctrlKey && event.keyCode == 89) Event(3160,'Refresh',{ q:'' }); };";
var acorn = require("acorn");
var tokens = acorn.parse(code);
function recursiveDump(token, level) {
var pad = Array(level).join(" ");
console.log(pad + "- token");
console.log(pad + " - type: " + token.type);
console.log(pad + " - code: " + code.substr(token.start, token.end - token.start));
if (token.type === 'ExpressionStatement') {
if (token.expression.left) {
console.log(pad + " - children:");
recursiveDump(token.expression.left, level + 3);
recursiveDump(token.expression.right, level + 3);
console.log();
}
}
else if (token.type === 'IfStatement') {
console.log(pad + " - children:");
recursiveDump(token.test, level + 3);
recursiveDump(token.consequent, level + 3);
if (token.alternate !== null) {
recursiveDump(token.alternate, level + 3);
}
console.log();
}
else if (token.hasOwnProperty("body")) {
console.log(pad + " - children:");
var body = token.body;
if (! Array.isArray(body) && body.hasOwnProperty("body")) {
body = body.body;
}
body.forEach(function(token) {
recursiveDump(token, level + 3);
});
console.log();
}
}
tokens.body.forEach(function(token) {
recursiveDump(token, 0);
});
This was just a quick example of how to process subtokens in general. You can save all this work if you only need to handle top-level statements.

Why would we declare a 2nd variable in the below code?

Why would we declare a second variable (val) when we can use the parameter of the function as a variable?
Here's how it looks like on codecademy:
var divideByThree = function (number) {
var val = number / 3;
console.log(val);
};
divideByThree(6);
I've made some changes as below:
var divideByThree = function (number) {
number = number / 3;
console.log(number);
};
divideByThree(6);
And it works pretty fine!!
In your example, you do not need to preserve the original value of the parameter. However, you may find it easier to use extra variables in the future for more complicated functions.
Here is an example:
// This function uses the parameter "rawNumber" as a variable, but also uses an extra variable "number"
function TestThis(rawNumber, p) {
// Convert the input (string) to integer
// parseInt returns NaN or integer. Truncates decimals
var number = parseInt(rawNumber);
// Check to see if the result is NaN or is an integer
if (isNaN(number)) {
Log(rawNumber + " is not a number.", p); // Log is my imitation of console.log()
}
// will run if number is type int
else {
if (number > 0 && number <= 100) {
Log(rawNumber + " is a valid number.", p);
} else {
Log(rawNumber + " is not between 1 and 100.", p);
}
}
}
You can see this code working in this Fiddle.
In this function I used an extra variable called "number" in three different places. I didn't have to, but it was easier than typing isNaN(parseInt(rawNumber)) and if(parseInt(rawNumber) > 0 && parseInt(rawNumber) <= 100). Codecademy was probably decided to teach you this way because it is easier to realize you can simplify your code than to realize you can simplify a more complex code through the use of extra variables.
Also, JK Price's answer brings up a readability issue. Simply put, this code is easier to read and understand:
function Example(number) {
var processedNumber = 5/(Math.log(1/number*3.14 - 7));
console.log("Message: " + (processedNumber * 2));
console.log("Message: " + (processedNumber / 10));
}
This code might be a little harder:
function Example(number) {
console.log("Message: " + ((5/(Math.log(1/number*3.14 - 7)) * 2));
console.log("Message: " + ((5/(Math.log(1/number*3.14 - 7)) / 10));
}
Variables are supposed to help the programmer write better and describe a better story. You can't have the same actor play multiple characters! One thing it does is to help keep variables separate.
The variable val in this case helps abstract the logic and most importantly help in debugging. If this was a long script and you saw that number was not what you originally passed it, you might consider it to be an error.

regex for nested parenthesis

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.

Javascript function to convert UTF8 substring

Following up with JavaScript function to convert UTF8 string between fullwidth and halfwidth forms, this time I want to replace only part of the string.
I think I have found all the answers that I want (from previous post and Replace substring in string with range in JavaScript), but I just can't put it all together. Please take a look at the following demonstration:
// Extend the string object to add a new method convert
String.prototype.convert = function() {
return this.replace( /[\uff01-\uff5e]/g,
function(ch) { return String.fromCharCode(ch.charCodeAt(0) - 0xfee0); }
)
};
// Test and verify it's working well:
> instr = "!abc ABC!!abc ABC!"
"!abc ABC!!abc ABC!"
> instr.substr(5, 4)
"ABC!"
> instr.substr(5, 4).convert()
"ABC!"
// Great!
// Goal: define a decode method like this
String.prototype.decode = function(start, length) {
return this.replace(
new RegExp("^(.{" + start + "})(.{" + length + "})"), "$1" + "$2".convert());
};
// Test/verify failed:
> instr.decode(5, 4)
"!abc ABC!!abc ABC!"
// That failed, now define a test method to verify
String.prototype.decode = function(start, length) {
return this.replace(
new RegExp("^(.{" + start + "})(.{" + length + "})"), "$2".length);
};
> instr.decode(5, 4)
"2!abc ABC!"
I.e., I believe that all my string extending methods are defined properly (in the eyes of someone who doesn't know javascript several days ago). But when putting them together, they don't work as I expected (!abc ABC!!abc ABC!).
Further the last test, the one test with "$2".length, I just can't understand why "$2".length is 2 but not 4.
Please help me out.
Thanks a lot.
You can't do "$2".convert() and "$2".length when you define the regular expressions, it should be something like this
return this.replace(new RegExp(...), function(m1, m2) {
return m2.length;
});
so that the script worked dynamically on every matching result

Categories

Resources