Check if string exists in another string (not exactly equal) - javascript

I have this 2 strings:
var test = 'BN123';
var behaviour = 'BN***,TA****';
I need to check if behaviour contains a string with the same format as test.
On the behaviour, the BN and TA as to be equal, and the * means it can be any char. (behaviour comes from an API, so I never know what it has, this is just a test.)
In this case it should return true. Right now I'm only comparing is case behaviour as a single string, but I need to modify that:
isValidInput(behaviour, test) {
if (behaviour.length != test.length) {
return false;
}
for (var i = 0; i < behaviour.length; i++) {
if (behaviour.charAt(i) == '*') {
continue;
}
if (behaviour.charAt(i) != test.charAt(i)) {
return false;
}
}
return true;
}

You can use .some() of Array.prototype.
like below
function isValidInput(behaviour, string1) {
if (behaviour.length != string1.length) {
return false;
}
for (var i = 0; i < behaviour.length; i++) {
if (behaviour.charAt(i) == '*') {
continue;
}
if (behaviour.charAt(i) != string1.charAt(i)) {
return false;
}
}
return true;
}
var test = 'BN123';
var behaviour = 'BN***,TA****';
console.log(behaviour.split(',').some(x => isValidInput(x,test)));
console.log(behaviour.split(',').some(x => isValidInput(x,"test")));

The only issue I see with your implementation is that you're not allowing for the fact behaviour contains possible strings separated with a comma (or at least, that's how it looks to me). So you need to check each of them:
// Check one behaviour string from the list
function isOneValidInput(behaviour, string) {
if (behaviour.length != string.length) {
return false;
}
for (var i = 0; i < behaviour.length; i++) {
// Note we can easily combine those conditions, and use []
// with strings
if (behaviour[i] != '*' && behaviour[i] != string[i]) {
return false;
}
}
return true;
}
// Check all behaviour strings in a comma-separated one
function isValidInput(behaviours, string) {
return behaviours.split(",").some(function(behaviour) {
return isOneValidInput(behaviour, string);
});
}
var string = 'BN123';
var behaviour = 'BN***,TA****';
console.log(isValidInput(behaviour, string));
(I stuck to ES5 there because you seemed to be doing so.)

Is this what you want?
var test = 'BN123';
var behaviour = 'BN***,TA****';
var behaviours = behaviour.split(',');
var result = behaviours.map(b => {
if (b.length != test.length)
return false;
var pattern = b.split('*')[0];
return pattern === test.substring(0,pattern.length);
}).find(r => r === true) > -1;
console.log(result)

You can use the new .includes() method to see if a string is contained within another. Note that this is case sensitive. I have included two dodgied up behaviours to check the string against.
var string = 'BN123';
var behaviour1 = 'BN123,TA1234';
var behaviour2 = 'BN120,TA1230';
function testStr(behaviour,string) {
return behaviour.includes(string);
}
console.log(testStr(behaviour1,string)) // gives true
console.log(testStr(behaviour2,string)) // gives false

isValidInput(behaviour, string) {
var array = behaviour.split(",");
var flag = 0;
for(var i = 0;i< array.length;i++){
var now = array[i];
var _flag = 1;
if (now.length == string.length) {
for (var j = 0; j < now.length; j++) {
if (now.charAt(j) == '*') {
continue;
}
if (now.charAt(j) != string.charAt(j)) {
_flag = 0;
}
}
flag |= _flag;
}
}
return flag;
}

Try modify your behaviour to RegExp:
function checkFn(testStr) {
var behaviour = '(BN...)|(TA....)'
var r = new RegExp('^(' + behaviour + ')$')
return r.test(testStr)
}
checkFn('BN123') // true
checkFn('BN12') // false
checkFn('BN1234') // false
checkFn('TA1234') // true
checkFn('TA123') // false
checkFn('TA12345') // false
Or use this fn:
function checkFn(testStr) {
var behaviour = 'BN***,TA****'
behaviour = behaviour
.split(',')
.reduce((r, el) => {
r.push('(' + el.replace(/\*/g, '.') + ')')
return r
}, [])
.join('|')
var r = new RegExp('^('+behaviour+')$')
return r.test(testStr)
}

Related

Search if a string contains a substring in Javascript (partial search)

Yes I know we can use indexOf and includes or a regular expression to find weather a string is present in another string.
But we have a different requirement. We would like indexOf or includes function to return true even if partial string is matched not the whole world. Let me provide an example.
Let's say my username is "Animation". The string the I am entering is "sssrtAnimyt5678". Now as the string "sssrtAnimyt5678" contains "Anim" which is present in "Animation" we want the function to return true.
The problem with indexOf, includes and regular expression is it tries to find the whole word "Animation" but not the partial word "Anim". I even used KMP Algorithm and found out that even KMP searches for "Animation" not "Anim". Below is the implementation of KMP in Javascript.
var makeKMPTable = function(word) {
if(Object.prototype.toString.call(word) == '[object String]' ) {
word = word.split('');
}
var results = [];
var pos = 2;
var cnd = 0;
results[0] = -1;
results[1] = 0;
while (pos < word.length) {
if (word[pos - 1] == word[cnd]) {
cnd++;
results[pos] = cnd;
pos++;
} else if (cnd > 0) {
cnd = results[cnd];
} else {
results[pos] = 0;
pos++;
}
}
return results;
};
var KMPSearch = function(string, word) {
if(Object.prototype.toString.call(string) == '[object String]' ) {
string = string.split('');
}
if(Object.prototype.toString.call(word) == '[object String]' ) {
word = word.split('');
}
var index = -1;
var m = 0;
var i = 0;
var T = makeKMPTable(word);
while (m + i < string.length) {
if (word[i] == string[m + i]) {
if (i == word.length - 1) {
return m;
}
i++;
} else {
m = m + i - T[i];
if (T[i] > -1) {
i = T[i];
} else {
i = 0;
}
}
}
return index;
};
console.log(KMPSearch("sssrtAnimyt5678", "Animation")); // returns -1
So I would like to know if such kind of partial search is possible and if anybody can point me to such implementation details or algorithm it would be helpful.
Thanks in Advance.
Just check any possible substring.
const
hasCommon = (a, b) => {
for (let i = 0; i < a.length; i++) {
for (let j = i + 1; j <= a.length; j++) {
if (b.includes(a.slice(i, j))) return true;
}
}
return false;
};
console.log(hasCommon('Animation', 'sssrtAnimyt5678'));

check the alphabetical order

I am a newbie who is trying hard to have a grip on javascript. please help me to consolidate my fundamentals.
input will be a string of letters.
following are the requirements.
function should return true if following conditions satisfy:
letters are in alphabetical order. (case insensitive)
only one letter is passed as input. example :
isAlphabet ('abc') === true
isAlphabet ('aBc') === true
isAlphabet ('a') === true
isAlphabet ('mnoprqst') === false
isAlphabet ('') === false
isAlphabet ('tt') === false
function isAlphabet(letters) {
const string = letters.toLowerCase();
for (let i = 0; i < string.length; i++) {
const diff = string.charCodeAt(i + 1) - string.charCodeAt(i);
if (diff === 1) {
continue;
} else if (string === '') {
return false;
} else if (string.length === 1) {
return true;
} else {
return false;
}
}
return true;
}
It's generally a better practice to start your function off with dealing with the edge-cases rather than putting them somewhere in the middle. That way, the function returns as soon as it can - and it's a lot easier to read than a waterfall of if..else statements.
function isAlphabet(letters) {
if ("" == letters) {
return false;
}
if (1 == letters.length) {
return true;
}
const string = letters.toLowerCase();
// carry on with your loop here.
}
You've got the right idea, but it can be simplified to just fail on a particular error condition, i.e when a smaller character follows a larger one:
function isAlphabet(letters) {
const string = letters.toLowerCase();
let lastChar;
for (let i = 0; i < string.length; i++) {
// Grab a character
let thisChar = string.charCodeAt(i);
// Check for the failure case, when a lower character follows a higher one
if (i && (thisChar < lastChar)) {
return false;
}
// Store this character to check the next one
lastChar = thisChar;
}
// If it got this far then input is valid
return true;
}
console.log(isAlphabet("abc"));
console.log(isAlphabet("aBc"));
console.log(isAlphabet("acb"));
You can use the simple way to achieve the same as below
function isAlphabet(inputString)
{
var sortedString = inputString.toLowerCase().split("").sort().join("");
return sortedString == inputString.toLowerCase();
}
console.log("abc = " + isAlphabet("abc"));
console.log("aBc = " + isAlphabet("aBc"));
console.log("acb = " + isAlphabet("acb"));
console.log("mnoprqst = " + isAlphabet("mnoprqst"));
Note: Mark the answer is resolves your problem.

Why indexOf in javascript not working?

I'm not sure what I'm doing wrong here. The first instance that I use indexOf it works perfectly fine, but when I use it the second time it's not returning the result that I'm expecting.
function mutation(arr) {
//return arr;
res = "";
for (var x=0; x<arr[1].split("").length; x++) {
if (arr[0].indexOf(arr[1].split("")[x]) !== -1) {
res += "t";
} else {
res += "f";
}
}
// res = ttt
if (res.indexOf("f") !== -1) {
return true;
} else {
return false;
}
}
mutation(["hello", "hey"]);
// this returns true instead of false
mutation(["floor", "loo"]);
// returns false instead of true
mutation should return false if an element from arr[1] is not present in arr[0] else return true.
your code isn't working because when you say:
res.indexOf("f") != -1
this means: "I found an f", but you're treating it as if it means "I did not find an f".
In your case that you want to return false if you find an 'f', but you're returning true. Flip your true and false cases:
if (res.indexOf("f") != -1) {
return false;
} else {
return true;
}
ALSO your for loop is wrong because x starts at 0, so you need to go to < length not <= length of your string.
for (var x=0; x < arr[1].split("").length; x++) {
and now your code works as you wanted it to.
Just edited your code. Click on the <p> to check:
function mutation(arr) {
//return arr;
res = "";
for (var x=0; x< arr[1].split("").length; x++) {
res += arr[0].indexOf(arr[1].split("")[x]) > -1 ? 't' : 'f';
}
return res.indexOf('f') > -1;
}
$('p').click(function(){
alert(mutation(["hello", "hey"]));
alert(mutation(["floor", "loo"]));
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Click me</p>
If you simplify the logic a bit, that's easier to check:
function mutation(arr) {
return arr[1].split('').reduce(function(res, x) {
return arr[0].indexOf(x) >= 0;
}, true);
}
Thanks Leon for the correction.
I tried to not chance your logic, the mistake are:
You're trying to compare with all characters on the array[0], not only the first.
If you find a character equals on the first character on array[0] you should return true.
Correct code:
function mutation(arr) {
res = "";
for (var x=0; x<=arr[1].split("").length; x++) {
if (arr[0].split("")[0].indexOf(arr[1].split("")[x]) !== -1) {
return true;
}
}
return false;
}

checking strings in an array

I'm trying to see if the string in the first element of the array contains all of the letters of the string in the second element of the array.
For example
['hello', 'hey'] = false;
['Army', 'Mary'] = true;
Here is my code
function mutation(arr) {
a = arr[0].toLowerCase().split("");
b = arr[1].toLowerCase().split("");
for(i = 0; i < a.length; i++){
if(b.indexOf(a[i]) != -1){
console.log('true');
} else {
console.log('false');
}
}
}
mutation(['Army', 'Mary']);
UPDATED
I need to see if element 1 contains all the letters for element 2 before I return back anything.
This would do, I'm sure there are better and optimal solutions though,
1) Storing the return result in a boolean, as var result = true;.
2) Check if both the Strings are equal/same, no need to loop, return the result which is true.
3) loop through each characters and see if the target element contains them, if found a mismatch set, result to false, break and return result.
function mutation(arr) {
a = arr[0].toLowerCase().split("");
b = arr[1].toLowerCase().split("");
var result = true;
if(a === b)
return result;
for(i = 0; i < a.length; i++){
if(b.indexOf(a[i]) === -1){
result = false;
break;
}
}
return result;
}
mutation(['Army', 'Mary']);
UPDATE Added a condition if (a === b) return true; to skip for loop.
No need of loop, you can take advantage of array functions.
Steps
Sort both arrays
Cast to the string
Check if strings2 contains string1
function mutation(arr) {
var a = arr[0].toLowerCase().split(''),
b = arr[1].toLowerCase().split('');
// For exact equality
return a.sort().toString() === b.sort().toString();
// return b.sort().toString().indexOf(a.sort().toString()) > -1;
}
document.write('Army and Mary: ' + mutation(['Army', 'Mary'])); // true
document.write('<br />a and b: ' + mutation(['a', 'b'])); // false
document.write('<br />ab and abc: ' + mutation(['ab', 'abc'])); // false
Simply you need to loop throught the second element letters and return false if a character doesn't exist in first element, or continue the loop if it exists.
Then check if the counter is equal to your string length then it contains all the given letters and return true:
function mutation(arr) {
a = arr[1].toLowerCase().split("");
b = arr[0].toLowerCase().split("");
if (a === b) return true;
for (i = 0; i < a.length; i++) {
if (b.indexOf(a[i]) === -1) {
return false;
}
}
if (i === a.length) {
return true; // all the letteers of element one exists in the second element
}
}
if (mutation(['Army', 'Mary'])) {
alert("Element one contains all letters of second element !");
} else {
alert("Sorry!");
}
Note:
Make sure you loop throught the second element characters and not the first one, see the a = arr[1].toLowerCase().split("");.
//mutation function work ignoring case and order of character in strings
function mutation(arr) {
var first = arr[0].toLowerCase();
var second = arr[1].toLowerCase();
for(var i = 0; i < second.length; i++){
if(first.indexOf(second[i]) == -1){
return false;
}
}
return true;
}
//this returns true
mutation(["hello", "ol"]);

all valid combinations of n-pair of parenthesis

I am learning js now..
I am trying to write a simple js programme..
what I am trying to do is to print all valid combinations of n-pair
of parenthesis(properly opened and closed)
eg (), (()()),(())
i have written the logic can you tell me whether its correct or not
https://jsfiddle.net/e7mcp6xb/
module.exports = Parentheses = (function() {
var _isParenthesesMatch = function(str) {
var parentheses = str.length;
var rightParentheses = '(';
var leftParentheses = ')';
var rightCount = 0;
var leftCount = 0;
for(i=0;i<=str.length;i++){
if(rightParentheses == str.charAt(i))
{
rightCount++;
}
else if(leftParentheses == str.charAt(i))
{
leftCount++;
}
}
if(rightCount == leftCount){
return true;
}
else(rightCount != leftCount){
return false;
}
}
}());
The check is wrong, but You can fix it easily: In each step of the for loop the number of opening parenthesis cannot be smaller than the number of closing ones:
if (rightCount < leftCount)
return false;
The whole function should look like this:
function(str) {
var rightParentheses = '(';
var leftParentheses = ')';
var rightCount = 0;
var leftCount = 0;
for (var i = 0; i <= str.length; i++) {
if (rightParentheses == str.charAt(i))
rightCount++;
else if (leftParentheses == str.charAt(i))
leftCount++;
if (rightCount < leftCount)
return false;
}
return rightCount == leftCount;
}
If You'd like to generate all valid strings, you can use this function:
function nPair(n) {
if (n == 0)
return [""];
var result = [];
for (var i = 0; i < n; ++i) {
var lefts = nPair(i);
var rights = nPair(n - i - 1);
for (var l = 0; l < lefts.length; ++l)
for (var r = 0; r < rights.length; ++r)
result.push("(" + lefts[l] + ")" + rights[r]);
}
return result;
}
// result of nPair(3):
// ["()()()", "()(())", "(())()", "(()())", "((()))"]
Try this, i have modified your code a little bit. Modification and its explanation is marked in comments.
module.exports = Parentheses = (function() {
var _isParenthesesMatch = function(str) {
var parentheses = str.length;
var rightParentheses = '(';
var leftParentheses = ')';
var count=0;
for(i=0;i<str.length;i++){
//this is to check valid combination start always from ( and end with )
if(str.charAt(0)==rightParentheses && str.length-1==leftParentheses)
{
if(rightParentheses == str.charAt(i))
{
count++; //this will calculate how many times rightParentheses is present & increment count by 1
}
else if(leftParentheses == str.charAt(i))
{
count--; //this will simply decrement count to match valid sequence
}
}
if(count==0){
return true;
}
}
}());
Your function is wrong, try checking if left and right parenthesis and balanced:
function isValid(str){
var stripedStr = str.replace(/[^\(\)]+/g, '');
return stripedStr.split('').reduce(function(a, b){
return a > -1 ? b === '(' ? a + 1 : a - 1 : -1;
}, 0) === 0;
}
stripedStr - use replace() to remove any characters that are not ( or ).
split('') - returns an array so we can use reduce.
reduce() - applies a function against an accumulator and each value of the array (from left-to-right) has to reduce it to a single value.
The reduce starts with 0 as initial value and in the reduce function we count parenthesis
(+1 for (, -1 for ) )
Our string is valid if our counter never goes below 0 and we end up with 0.
You can write the reduce function like this too:
function(previousValue, currentValue){
if (previousValue > -1){
if (currentValue === '('){
return previousValue + 1;
} else {
return previousValue - 1;
}
}
return -1;
}
This is equivalent to:
function(a, b){
return a > -1 ? b === '(' ? a + 1 : a - 1 : -1;
}
It is wrong, because your function will return true for this example ))(( or this ())(()

Categories

Resources