javascript match implicit variable - javascript

I'm unable to determine if there is an implicit variable for match results in javascript.
The resulting code which I'm looking for is this:
if(line.match(/foo{bar}/)) {
console.log(bar_variable)
}
the referenced ^ bar_variable should contain the match group result.
Is there anything like this?

No, there is not. String.match() returns:
An Array whose contents depend on the presence or absence of the global (g) flag, or null if no matches are found.
So you could do something like:
if (bar_variable = line.match(/foo{bar}/)) {
console.log(bar_variable)
}
To avoid a global symbol you could do something like this, but it does make it a bit uglier:
{
let bar_variable;
if (bar_variable = line.match(/foo{bar}/)) {
console.log(bar_variable);
}
}
As far as I know you can't do if (let x = ...) but I could be wrong.

Related

Iterate over RegExp.exec(...)

From the RegExp.exec page on MDN, it gives the following example of iterating through a match with the g flag set:
const regex1 = RegExp('foo*', 'g');
const str1 = 'table football, foosball';
let array1;
while ((array1 = regex1.exec(str1)) !== null) {
console.log(`Found ${array1[0]}. Next starts at ${regex1.lastIndex}.`);
// expected output: "Found foo. Next starts at 9."
// expected output: "Found foo. Next starts at 19."
}
I have two questions about this code. The first one is why the !=== null is used here, why wouldn't the while loop be properly coded as:
while (array1 = regex1.exec(str1)) { // implicitly casts to boolean?
console.log(`...`);
}
The above seems much more readable to me, but was wondering why the MDN docs used the first approach? Second, is it possible to declare and define the variable directly in the while loop? Something like:
while (let array1 = regex1.exec(str1)) { // don't need the `let array1` above?
console.log(`...`);
}
Or is that not supported in the JS language?
Why the !== null is used here...?
True, in this case it is not needed. .exec() returns either an array or null, and since arrays are always truthy there is no need to explicitly compare with null.
Is it possible to declare and define the variable directly in the while loop?
No. If you want that, then turn to the for loop, which does support this:
for (let array1; array1 = regex1.exec(str1); null) {
console.log(`...`);
}
This does indeed have the advantage that array1 has a more restricted scope. NB: I provided null to stress that the third part of the for header is intentionally unused.

Conditional grammar rule in PEGjs

I'm trying to implement a simple DSL that parses basic arithmetic expressions. This needs to be done in the browser, so I'm using PEGjs to generate the parser.
Terms in the expression can be numbers (integers or real), variables (variables are properties on a context object passed to the parser), conditionals or properties accessed via dot notation.
I want the conditionals to look like this condition?value, where if condition is true, the term equates to value. The variables on either side of the ? could also be dot notation accessed properties of an object like this object.property1?object.property2.
So if the parser is passed an object like this:
context = {
depth: 100,
material: {
thickness: 20
include: true
}
edge: {
face: 4.5
}
}
The expression:
500 + depth + material.include?edge.face + material.thickness should equate to 624.5.
I've been using the PEGjs online editor. I've tried lots of different approaches, but I can't seem to nail the conditional. Everything else works. Here are the relevant rules:
Variable "variable"
= variable:identifier accessor:("." identifier)* {
var result = context[variable], i
for (i = 0; i < accessor.length; i++) {
result = result[accessor[i][1]]
}
return result
}
identifier
= identifier:$([0-9a-zA-Z_\$]+)
Conditional
= condition:Variable "?" value:Variable {
return condition ? value : 0
}
I've looked at the example grammar for javascript in the PEGjs github repo, and the conditional rule looks a lot like what I've got here, but I still can't get it to work.
What would be the correct way to implement a conditional statement like the one I've described in a PEGjs rule?
I know that this is a bit late, but the issue is that your variable is a string evaluating to "material.include".
Look at this code:
var result = context[variable], i
You are trying to access a property named "material.include" from your context object, which would look like this:
{
"material.include": true
}
Rather than trying to access the object referenced by the "material" property, and then the "include" property off the resulting object, which would look like this:
{
"material": {
"include": true
}
}
The solution would be to split the variable string by "." characters and then recursively find your property:
Variable "variable"
= variable:identifier accessor:("." identifier)* {
var path = variable.split(".");
var result = path.reduce( (nextObject, propName) => nextObject[propName], context );
for (var i = 0; i < accessor.length; i++) {
result = result[accessor[i][1]]
}
return result
}
Note that this solution is not complete, as it will cause an error if you try to access material.include where material is never defined in your context. You may want to add additional error handling, but it does work for the given example.

Intersecting texts to find common words

I'm trying to find out which would be the most optimal way of intersection a set of texts and find the common words in them. Given this scenario:
var t1 = 'My name is Mary-Ann, and I come from Kansas!';
var t2 = 'John, meet Mary, she comes from far away';
var t3 = 'Hi Mary-Ann, come here, nice to meet you!';
intersection result should be:
var result =["Mary"];
It should be able to ignore punctuation marks like .,!?-
Would a solution with regular expressions be optimal?
Here's a tested solution :
function intersect() {
var set = {};
[].forEach.call(arguments, function(a,i){
var tokens = a.match(/\w+/g);
if (!i) {
tokens.forEach(function(t){ set[t]=1 });
} else {
for (var k in set){
if (tokens.indexOf(k)<0) delete set[k];
}
}
});
return Object.keys(set);
}
This function is variadic, you can call it with any number of texts :
console.log(intersect(t1, t2, t3)) // -> ["Mary"]
console.log(intersect(t1, t2)) // -> ["Mary", "from"]
console.log(intersect()) // -> []
If you need to support non English languages, then this regex won't be enough because of the poor support of Unicode in JavaScript regexes. Either you use a regex library or you define your regex by explicitly excluding characters as in a.match(/[^\s\-.,!?]+/g); (this will probably be enough for you) .
Detailed explanation :
The idea is to fill a set with the tokens of the first text and then remove from the set the tokens missing in the other texts.
The set is a JavaScript object used as a map. Some purists would have used Object.create(null) to avoid a prototype, I like the simplicity of {}.
As I want my function to be variadic, I use arguments instead of defining the passed texts as explicit arguments.
arguments isn't a real array, so to iterate over it you need either a for loop or a trick like [].forEach.call. It works because arguments is "array-like".
To tokenize, I simply use match to match words, nothing special here (see note above regarding better support of other languages, though)
I use !i to check if it's the first text. In that case, I simply copy the tokens as properties in the set. A value must be used, I use 1. In the future, ES6 sets will make the intent more obvious here.
For the following texts, I iterate over the elements of the sets (the keys) and I remove the ones which are not in the array of tokens (tokens.indexOf(k)<0)
Finally, I return the elements of the sets because we want an array. The simplest solution is to use Object.keys.

Accessing nested objects in javascript

I am trying to run some JavaScript, but it is not working.
I have an object with two properties that are also objects.
var people = {
me: {
name: "Hello"
},
molly: {
name: "Molly"
}
};
And I am trying to make a function that uses a for/in statement and an if statement to list the properties of people.
var search = function (x) {
for (var a in people) {
if (people.a.name === x) {
return people.a;
}
}
};
So the function loops through the properties of people and assigns them to the variable a. Therefore people.a will be equal to a property of people. Then the function returns the property (people.a).
So if I type in me as parameter x, will the function should return the properties for the me object? I put this code in jsLint and jsHint and it passed, but I decided to remove the corrections because they were useless.
I then want to print the object properties in the browser:
var print = search("me");
document.getElementById("p").innerHTML(print);
I have this linked to an html document, with a tag id "p". I have tested javascript in the html document already, so I know that the javascript document is linked properly.
But the code will not work. Does anyone have any suggestions?
I have it working now thanks to the answers. But I thought that it would only print "Hello" to the screen, not { name: "Hello"}.
You need to use people[a], not people.a. The former looks for a property with the name of the value stored in a; the latter looks for a property literally named "a", which of course doesn't exist.
for (var a in people) {
if (people[a].name === x) {
return people[a];
}
}
Fiddle here.
Also, I think you meant search("Hello"), right? If not, then it would just be var search = function(x) { return people[x]; }.
people.a.name
you need to use the bracket operator if you want to access an item by name. Using people.a is literally searching for a member named 'a' instead of a member with the same name as the value of a.
Try:
people[a].name
instead.
4 errors in your code:
replace people.a with people[a]
replace innerHTML() with innerHTML
set HTML like this: document.getElementById("p").innerHTML = print.name;
As in a previous answer, search by name
Code: http://jsfiddle.net/nabil_kadimi/vVSPG/

JavaScript: alert object name as a string

I'm trying to alert any JavaScript object as a string, in a function. This means if the parameter given to the function is window.document, the actual object, it should alert "window.document" (without quotes) as a literal string.
The following calls...
example(window);
example(window.document);
example(document.getElementById('something'));
...calling this function...
function example(o) {/* A little help here please? */}
...should output the following strings...
window
window.document
document.getElementById('something')
I've attempted to do this with combinations of toString() and eval() among some more miscellaneous shots in the dark without success.
No need insane backwards compatibility, newer ECMAScript / JavaScript features/functions are fine. Feel free to inquire for clarifications though the goal should be pretty straight forward.
This is not possible to do in a self contained script.
If using a preprocessor would be an option, then you could write one which converts example(whatever) into example('whatever'). Other than that I'm afraid you're out of luck.
The first problem is that objects don't have names.
The second problem is that from your examples, you're not really wanting to print the (nonexistent) name of an object, you want to print the expression that evaluated into a reference to an object. That's what you're trying to do in this example:
example(document.getElementById('something'));
For that to print document.getElementById('something'), JavaScript would have had to keep the actual text of that expression somewhere that it would make available to you. But it doesn't do that. It merely evaluates the parsed and compiled expression without reference to the original text of the expression.
If you were willing to quote the argument to example(), then of course it would be trivial:
example( "document.getElementById('something')" );
Obviously in this case you could either print the string directly, or eval() it to get the result of the expression.
OTOH, if you want to try a real hack, here's a trick you could use in some very limited circumstances:
function example( value ) {
var code = arguments.callee.caller.toString();
var match = code.match( /example\s*\(\s*(.*)\s*\)/ );
console.log( match && match[1] );
}
function test() {
var a = (1);
example( document.getElementById('body') );
var b = (2);
}
test();
This will print what you wanted:
document.getElementById('body')
(The assignments to a and b in the test() function are just there to verify that the regular expression isn't picking up too much code.)
But this will fail if there's more than one call to example() in the calling function, or if that call is split across more than one line. Also, arguments.callee.caller has been deprecated for some time but is still supported by most browsers as long as you're not in strict mode. I suppose this hack could be useful for some kind of debugging purposes though.
Don't know why you need this, but you can try walking the object tree recursively and compare its nodes with your argument:
function objectName(x) {
function search(x, context, path) {
if(x === context)
return path;
if(typeof context != "object" || seen.indexOf(context) >= 0)
return;
seen.push(context);
for(var p in context) {
var q = search(x, context[p], path + "." + p);
if(q)
return q;
}
}
var seen = [];
return search(x, window, "window");
}
Example:
console.log(objectName(document.body))
prints for me
window.document.activeElement

Categories