'SyntaxError: Invalid shorthand property initializer' when using regex - javascript

I'm trying to validate a pin using the following function
function validate(num){
num.length === 4 || num.length === 6 ? {
regex = /\d+/,
regex:test(num)
}
:
false
}
however I'm getting this error and I can't figure out why
/home/runner/index.js:3
regex = /\d+/,
^^^^^^^^^^^^^
SyntaxError: Invalid shorthand property initializer

As others have pointed out, you can't put statements in conditional expressions (or any other expression, either), you can only put expressions.
The error you're getting is because it thinks you're trying to write an object literal, but you can't have assignments inside object literals.
You can use a normal if statement:
if (num.length == 4 || num.length == 6) {
var regex = /\d+/;
return regex.test(num);
} else {
return false;
}
But there's no need for the conditional at all, you can test the length in the regexp itself.
function validate(num) {
return /^\d{4}$|^\d{6}$/.test(num);
}

While I cannot recommend such here, it is important to keep in mind that a function expression can be used in an expression context. This is done all the time, such as for callbacks, and the same concept is transferable elsewhere..
Here is a minimal conversion of the original (which maintains as many of the original's bugs and other features, except where they caused parse errors) showing a function expression. This specific case is also called an "IIFE".
function validate(num){
return num.length === 4 || num.length === 6
? (function() {
let regex = /\d+/;
return regex.test(num);
})()
: false;
}

You cannot use the ?: operator with statements; only expressions.
However, there is no need to define a variable for your regex here. You can just call .test on the regex literal directly:
function validate(num){
return num.length === 4 || num.length === 6 ? /\d+/.test(num) : false
}
Even better, just use the && operator, which is logically equivalent here:
function validate(num){
return (num.length === 4 || num.length === 6) && /\d+/.test(num);
}

Related

Javascript - is there a better way to check an string instead of indexOf

I use this code and My question would be if there is a better way to check a string than indexOf:
if(documentFile.ending.indexOf('pdf') > -1 || documentFile.ending.indexOf('PDF') > -1 || documentFile.ending.indexOf('docx') > -1)
ES6 has boolean function. Use:
if ( documentFile.ending.includes('pdf') ) { }
Or for regex:
if ( documentFile.ending.match(/your-regex/) { }
Example spec: https://developer.mozilla.org/nl/docs/Web/JavaScript/Reference/Global_Objects/String/includes
If you are using ES6 then you may want to look at String.prototype.includes
var str = 'To be, or not to be, that is the question.';
console.log(str.includes('To be')); // true
In ES6 you have better option to use "includes"
otherwise use regex
if(/pdf/i.test(documentFile.ending))
Well, indexOf is really fast, a lot faster than using a regular expression. But something like /pdf$/i.test(str) lets you test the end as well as giving you case-insensitivity. But you could be more precise:
function endsWith(str, ending) {
return str != null
&& ending != null
&& ending.length <= str.length
&& str.lastIndexOf(ending) === str.length - ending.length;
}
Note the ending.length <= str.length which is there so that you don't do something like endsWith("", "a") and get true. :)

unexpected results in evaluation of chains logical expressions javascript

I am writing a program to identify special numbers according to the criteria laid out in this code wars kata:
http://www.codewars.com/kata/catching-car-mileage-numbers
Here is a link to my full code and tests:
http://www.codeshare.io/UeXhW
I have unit tested my functions which test for each of the special number conditions and they appear to be working as expected. However, I have a function:
function allTests(number, awesomePhrases){
var num = number.toString().split('');
// if any criteria is met and the number is >99 return true
return number > 99 && (allZeros(num) || sameDigits(num) || incrementing(num) || decrementing(num) || palindrome(number) || matchPhrase(number, awesomePhrases)) ? true : false;
}
which determines if any of the criteria of being a special number is met and that's not working as expected. For example, when I tested the allZeros() function on 7000 it returned true, but alltests(7000) is returning false. Is there something about how chains of logical expressions are evaluated that I don't understand or is the problem something else?
I have looked at W3schools and MDN to try and diagnose the problem.
Change all your !== to != will do.
False results as long as allTests() executes with a second argument even it it's the empty string, as follows:
allTests(7000,"");
If the function is called with just one argument, i.e. the number, expect this error:
Uncaught TypeError: Cannot read property 'length' of undefined
The error message refers to one of the functions in the logic chain, namely matchPhrase() which expects two parameters: number and awesomePhrases. If instead of providing an empty string, you use null, you'll also get the same error message.
JavaScript doesn't support the concept of default parameters -- at least not in a way that one might expect; the parameters default to undefined. But there is a way to work around this hurdle and improve the code so that one may avoid this needless error. Just change matchPhrase() as follows:
function matchPhrase(number, awesomePhrases){
awesomePhrases = typeof awesomePhrases !== 'undefined' ? awesomePhrases : "";
for(var i = 0, max=awesomePhrases.length; i < max; i++){
if(number == awesomePhrases[i]){
return true;
}
}
return false;
}
The first statement accepts the second argument's value as long as it is not the undefined value; if so, then the variable gets set to the empty string. (Source for technique: here).
To make the code more readily comprehensible, I suggest rewriting allTests() as follows, so that the code follows a more explicit self-documenting style:
function allTests(number, awesomePhrases){
var arrDigits = number.toString().split('');
// if any criteria is met and the number is >99 return true
return number > 99 && (allZeros( arrDigits ) || sameDigits( arrDigits ) || incrementing( arrDigits ) || decrementing( arrDigits) || palindrome(number) || matchPhrase(number, awesomePhrases)) ? true : false;
}
This function takes a number and uses its toString() method to convert the number to a string. The resulting string which is not visible will split itself on the empty string so that the result of arrDigits is an array of numerical strings, each one consisting of just one digit. This is the point of origin for the ensuing problem with allZeros() which compares a stringified digit with a number.
Incidentally, in the function allTests() there is an awfully lengthy ternary expression. The syntax is fine, but you might wish to rewrite the code as follows:
function getCriteriaStatus(arrDigits,number,awesomePhrases) {
var criteria = new Array();
criteria[0] = allZeros( arrDigits );
criteria[1] = sameDigits( arrDigits );
criteria[2] = incrementing( arrDigits );
criteria[3] = decrementing( arrDigits);
criteria[4] = palindrome(number);
criteria[5] = matchPhrase(number, awesomePhrases);
var retval = false;
for (var i=0, max=6; i < max; i++) {
if ( criteria[i] == true ) {
retval = true;
break;
}
}
return retval;
}
function allTests(number, awesomePhrases){
var arrDigits = number.toString().split('');
var criteria_met = getCriteriaStatus(arrDigits,number,awesomePhrases);
return (number > 99 && criteria_met);
}
To obtain the desired true result from allTests() when it invokes allZeros(), rather than complicate the code by using parseInt(), I suggest rewriting allZeros() and any other functions containing code that compares a numerical string value with a number by changing from the identity operator to the equality operator. The change involves merely replacing === with == as well as replacing !== with !=. The code that compares values of the same data type, using the identity operators, those operators may, and probably should, remain unchanged. (See here).

What a strange syntax?

I've found unknown for me code construction on JQuery site. After some formatting it looks like:
function (a,c) {
c==null && (c=a,a=null);
return arguments.length>0
? this.bind(b,a,c)
: this.trigger(b)
}
What does the first line of the function mean? Is it any trick or standard JS code construction?
It's a trick that uses boolean short-circuit evaluation to only do the second half if the first evaluates to true. Perl has this commonly:
<something> or die
where if the first statement failed, the program ends.
Read it as
if (c == null) { c = a; a = null; }
That's an ugly way to write
if(c==null) {
c = a;
a = null;
}
This utilizes the fact, that the second part of boolean && will be executed if, and only if the first part evaluates to true.
The expression uses two JavaScript features :
short circuit evaluation of boolean operators: in statement context, a && (b); is equivalent to if (a) (b);
the comma operator to group assignment expressions: in statement context, a=b,b=c; is equivalent to { a=b; b=c }
As a result the expression is equivalent to:
if (c == null) {
c = a
a = null
}

Can I get the "value" of an arbitrary statement in JavaScript (like eval does, but without eval)

In JavaScript is there a way to get the "value" of a statement in the same way that function() { return eval("if (true) { 1 }"); } returns "1";
function() { return if (true) { 1 } } and all similar permutations I've tried are not valid syntax.
Is eval just blessed with special powers to determine the "last" value of a statement in an expression?
Use case is a REPL that evaluates arbitrary expressions and returns the result. eval works, but I want to wrap it in function.
function(expr) { return eval(expr); }
But that really doesn't do anything more than what eval does, so I'm guessing you must want to do things with the return value of eval before returning it?
E.g.:
function custom_eval(expr)
{
var result = eval(expr);
if ((typeof result))=="string")
{
alert("The expression returned a string value of: " + result);
}
if ((typeof result))=="number")
{
alert("The expression returned a number with value: " + result);
}
//and so on and so forth...
return result;
}
var bob = custom_eval("x=\"bob\";x");
alert(bob);
(More on the typeof operator)
To evaluate arbitrary javascript code in javascript you have three options
eval. This is usually considered as "dangerous", but since javascript is executed on the client's computer, they can only harm themselves (unless you provide clients with a way to share their codes).
Function constructor. The same concerns apply.
write a javascript interpreter. This is definitely tricky for "arbitrary" code.
You can use || to get the first value that isn't null/undefined/0:
var t = 1 || 'b' || 3 || 'd'; // assigns 1
var t = 0 || null || undefined || 'd'; // assigns d
You can use && to get the last value, if no short-circuiting null/undefined/0 is found first:
var t = 1 && 'b' && 3 && 'd'; // assigns d
var t = 0 && null && undefined && 'd'; // assigns 0

Count number of matches of a regex in Javascript

I wanted to write a regex to count the number of spaces/tabs/newline in a chunk of text. So I naively wrote the following:-
numSpaces : function(text) {
return text.match(/\s/).length;
}
For some unknown reasons it always returns 1. What is the problem with the above statement? I have since solved the problem with the following:-
numSpaces : function(text) {
return (text.split(/\s/).length -1);
}
tl;dr: Generic Pattern Counter
// THIS IS WHAT YOU NEED
const count = (str) => {
const re = /YOUR_PATTERN_HERE/g
return ((str || '').match(re) || []).length
}
For those that arrived here looking for a generic way to count the number of occurrences of a regex pattern in a string, and don't want it to fail if there are zero occurrences, this code is what you need. Here's a demonstration:
/*
* Example
*/
const count = (str) => {
const re = /[a-z]{3}/g
return ((str || '').match(re) || []).length
}
const str1 = 'abc, def, ghi'
const str2 = 'ABC, DEF, GHI'
console.log(`'${str1}' has ${count(str1)} occurrences of pattern '/[a-z]{3}/g'`)
console.log(`'${str2}' has ${count(str2)} occurrences of pattern '/[a-z]{3}/g'`)
Original Answer
The problem with your initial code is that you are missing the global identifier:
>>> 'hi there how are you'.match(/\s/g).length;
4
Without the g part of the regex it will only match the first occurrence and stop there.
Also note that your regex will count successive spaces twice:
>>> 'hi there'.match(/\s/g).length;
2
If that is not desirable, you could do this:
>>> 'hi there'.match(/\s+/g).length;
1
As mentioned in my earlier answer, you can use RegExp.exec() to iterate over all matches and count each occurrence; the advantage is limited to memory only, because on the whole it's about 20% slower than using String.match().
var re = /\s/g,
count = 0;
while (re.exec(text) !== null) {
++count;
}
return count;
(('a a a').match(/b/g) || []).length; // 0
(('a a a').match(/a/g) || []).length; // 3
Based on https://stackoverflow.com/a/48195124/16777 but fixed to actually work in zero-results case.
Here is a similar solution to #Paolo Bergantino's answer, but with modern operators. I'll explain below.
const matchCount = (str, re) => {
return str?.match(re)?.length ?? 0;
};
// usage
let numSpaces = matchCount(undefined, /\s/g);
console.log(numSpaces); // 0
numSpaces = matchCount("foobarbaz", /\s/g);
console.log(numSpaces); // 0
numSpaces = matchCount("foo bar baz", /\s/g);
console.log(numSpaces); // 2
?. is the optional chaining operator. It allows you to chain calls as deep as you want without having to worry about whether there is an undefined/null along the way. Think of str?.match(re) as
if (str !== undefined && str !== null) {
return str.match(re);
} else {
return undefined;
}
This is slightly different from #Paolo Bergantino's. Theirs is written like this: (str || ''). That means if str is falsy, return ''. 0 is falsy. document.all is falsy. In my opinion, if someone were to pass those into this function as a string, it would probably be because of programmer error. Therefore, I'd rather be informed I'm doing something non-sensible than troubleshoot why I keep on getting a length of 0.
?? is the nullish coalescing operator. Think of it as || but more specific. If the left hand side of || evaluates to falsy, it executes the right-hand side. But ?? only executes if the left-hand side is undefined or null.
Keep in mind, the nullish coalescing operator in ?.length ?? 0 will return the same thing as using ?.length || 0. The difference is, if length returns 0, it won't execute the right-hand side... but the result is going to be 0 whether you use || or ??.
Honestly, in this situation I would probably change it to || because more JavaScript developers are familiar with that operator. Maybe someone could enlighten me on benefits of ?? vs || in this situation, if any exist.
Lastly, I changed the signature so the function can be used for any regex.
Oh, and here is a typescript version:
const matchCount = (str: string, re: RegExp) => {
return str?.match(re)?.length ?? 0;
};
('my string'.match(/\s/g) || []).length;
This is certainly something that has a lot of traps. I was working with Paolo Bergantino's answer, and realising that even that has some limitations. I found working with string representations of dates a good place to quickly find some of the main problems. Start with an input string like this:
'12-2-2019 5:1:48.670'
and set up Paolo's function like this:
function count(re, str) {
if (typeof re !== "string") {
return 0;
}
re = (re === '.') ? ('\\' + re) : re;
var cre = new RegExp(re, 'g');
return ((str || '').match(cre) || []).length;
}
I wanted the regular expression to be passed in, so that the function is more reusable, secondly, I wanted the parameter to be a string, so that the client doesn't have to make the regex, but simply match on the string, like a standard string utility class method.
Now, here you can see that I'm dealing with issues with the input. With the following:
if (typeof re !== "string") {
return 0;
}
I am ensuring that the input isn't anything like the literal 0, false, undefined, or null, none of which are strings. Since these literals are not in the input string, there should be no matches, but it should match '0', which is a string.
With the following:
re = (re === '.') ? ('\\' + re) : re;
I am dealing with the fact that the RegExp constructor will (I think, wrongly) interpret the string '.' as the all character matcher \.\
Finally, because I am using the RegExp constructor, I need to give it the global 'g' flag so that it counts all matches, not just the first one, similar to the suggestions in other posts.
I realise that this is an extremely late answer, but it might be helpful to someone stumbling along here. BTW here's the TypeScript version:
function count(re: string, str: string): number {
if (typeof re !== 'string') {
return 0;
}
re = (re === '.') ? ('\\' + re) : re;
const cre = new RegExp(re, 'g');
return ((str || '').match(cre) || []).length;
}
Using modern syntax avoids the need to create a dummy array to count length 0
const countMatches = (exp, str) => str.match(exp)?.length ?? 0;
Must pass exp as RegExp and str as String.
how about like this
function isint(str){
if(str.match(/\d/g).length==str.length){
return true;
}
else {
return false
}
}

Categories

Resources