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

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'));

Related

Remove Last Character From String If It's a "!" Using For-Loop - JavaScript

I have
function remove(s) {
for (i = 0; i < s.length; i++) {
let lastChar = s.slice(-1);
if (lastChar === "!") {
s = s.substring(0, s.length - 1);
}
else {
return s;
}
}
return s;
}
And this is passing 105 tests but failing 1 on codewars.
The test that it's failing is:
Expected: '\'isl\'', instead got: '\'isl!\'' for when (s) is "isl!!!!!"
I can't figure out why, in this case, it's not removing the last character in the string.
This should be removing the last character in the string whenever it's !:
if (lastChar === "!") {
s = s.substring(0, s.length - 1);
}
I've also tried:
s = s.replace("!", "");
But same result. Any ideas?
Because you're increasing i and checking i < s.length on each loop. At one point, you remove a ! (thus shortening the string) and i is equal to s.length and you never check the last char.
There's no reason for i at all. (Or a for loop, but if that was the requirement in the challenge...)
If you step through it with your debugger, you'll see the problem. This version using console.log also shows the problem:
function remove(s) {
for (i = 0; i < s.length; i++) {
let lastChar = s.slice(-1);
if (lastChar === "!") {
s = s.substring(0, s.length - 1);
console.log(`i = ${i}, s = '${s}', s.substring(i) = '${s.substring(i)}'`);
}
else {
console.log(`returning '${s}'`);
return s;
}
}
console.log(`returning '${s}' at end, because ${i} >= ${s.length}`);
return s;
}
remove("isl!!!!!");
.as-console-wrapper {
max-height: 100% !important;
}
You can do this without using for loop.
const stringRemover (str) => {
if (str[str.length-1] === "!") {
return str.slice(0,str.length-1);
} else {
return str;
}
}
You can create a recursive function and check if the last char using CharAt if it is !. If it is so then again call the same function but with new string which is created after removing the last !
Not sure why the for is needed if the last character is needed
function remove(str) {
let getLastChar = str.charAt(str.length - 1);
if (getLastChar === '!') {
return remove(str.substring(0, str.length - 1))
} else {
return str;
}
}
console.log(remove("isl!!!!!"));
Here is codewars result
Here is result
As answered in a previous reply, i < s.length is checked in every iteration in a for loop.
Try this :
function remove(s) {
let a = s.length;
for (i = 0; i < a; i++) {
let lastChar = s.slice(-1);
if (lastChar === "!") {
s = s.substring(0, s.length - 1);
}
else {
return s;
}
}
return s;
}
#T.J. Crowder pointed me in the right direction, but he didn't provide an answer that followed my original logic (in this case I wanted to use a for-loop).
The key takeaway is that s = s.replace("!", ""); will work when i-- and s = s.replace(/!+$/g, '') will work when i++. Because, as far as I understand, the replace() method only replaces the first occurrence of the string, which is why we need i-- to force the loop to iterate backwards through the string, making sure that every occurance of "!" gets replaced.
I.e. this will work:
function remove(s) {
for (i = 0; i < s.length; i--) {
let lastChar = s.slice(-1);
if (lastChar === "!") {
s = s.replace("!", '')
}
else {
return s;
}
}
return s;
}
And this will also work:
function remove(s) {
for (i = 0; i < s.length; i++) {
let lastChar = s.slice(-1);
if (lastChar === "!") {
s = s.replace(/!+$/g, '');
}
else {
return s;
}
}
return s;
}

How do you iterate over an array every x spots and replace with letter?

/Write a function called weave that accepts an input string and number. The function should return the string with every xth character replaced with an 'x'./
function weave(word,numSkip) {
let myString = word.split("");
numSkip -= 1;
for(let i = 0; i < myString.length; i++)
{
numSkip += numSkip;
myString[numSkip] = "x";
}
let newString = myString.join();
console.log(newString);
}
weave("weave",2);
I keep getting an infinite loop. I believe the answer I am looking for is "wxaxe".
Here's another solution, incrementing the for loop by the numToSkip parameter.
function weave(word, numToSkip) {
let letters = word.split("");
for (let i=numToSkip - 1; i < letters.length; i = i + numToSkip) {
letters[i] = "x"
}
return letters.join("");
}
Well you need to test each loop to check if it's a skip or not. Something as simple as the following will do:
function weave(word,numSkip) {
var arr = word.split("");
for(var i = 0; i < arr.length; i++)
{
if((i+1) % numSkip == 0) {
arr[i] = "x";
}
}
return arr.join("");
}
Here is a working example
Alternatively, you could use the map function:
function weave(word, numSkip) {
var arr = word.split("");
arr = arr.map(function(letter, index) {
return (index + 1) % numSkip ? letter : 'x';
});
return arr.join("");
}
Here is a working example
Here is a more re-usable function that allows specifying the character used for substitution:
function weave(input, skip, substitute) {
return input.split("").map(function(letter, index) {
return (index + 1) % skip ? letter : substitute;
}).join("");
}
Called like:
var result = weave('weave', 2, 'x');
Here is a working example
You dont need an array, string concatenation will do it, as well as the modulo operator:
function weave(str,x){
var result = "";
for(var i = 0; i < str.length; i++){
result += (i && (i+1)%x === 0)?"x":str[i];
}
return result;
}
With arrays:
const weave = (str,x) => str.split("").map((c,i)=>(i&&!((i+1)%x))?"x":c).join("");
You're getting your word greater in your loop every time, so your loop is infinite.
Try something like this :
for(let k = 1; k <= myString.length; k++)
{
if(k % numSkip == 0){
myString[k-1]='x';
}
}
Looking at what you have, I believe the reason you are getting an error is because the way you update numSkip, it eventually becomes larger than
myString.length. In my code snippet, I make i increment by numSkip which prevents the loop from ever executing when i is greater than myString.length. Please feel free to ask questions, and I will do my best to clarify!
JSFiddle of my solution (view the developer console to see the output.
function weave(word,numSkip) {
let myString = word.split("");
for(let i = numSkip - 1; i < myString.length; i += numSkip)
{
myString[i] = "x";
}
let newString = myString.join();
console.log(newString);
}
weave("weave",2);
Strings are immutable, you need a new string for the result and concat the actual character or the replacement.
function weave(word, numSkip) {
var i, result = '';
for (i = 0; i < word.length; i++) {
result += (i + 1) % numSkip ? word[i] : 'x';
}
return result;
}
console.log(weave("weave", 2));
console.log(weave("abcd efgh ijkl m", 5));
You can do this with fewer lines of code:
function weave(word, numSkip) {
word = word.split("");
for (i = 0; i < word.length; i++) {
word[i] = ((i + 1) % numSkip == 0) ? "x" : word[i];
}
return word.join("");
}
var result = weave("weave", 2);
console.log(result);

Encryption... almost works

I wrote a simple script for a website called Codewars (here: https://www.codewars.com/kata/57814d79a56c88e3e0000786). The purpose of the function was to encrypt a string such that every second character would appear first, and then the rest of them. I tested many random strings of text; it worked for a while. But then, I tested a specific case with 17 characters: "maybe do i really", and it resulted in a character being dropped (notably a space). Initially, I thought the issue was that the .join method didn't allow a double space in a row, so I attempted to make my own function to mimic its functionality: it did not solve the problem. Could anyone answer why this specific string loses a character and returns a wrong encryption? My jsfiddle is here: https://jsfiddle.net/MCBlastoise/fwz62j2g/
Edit: I neglected to mention that it runs a certain number of times based on parameter n, encrypting the string multiple times per that value.
And my code is here:
function encrypt(text, n) {
if (n <= 0 || isNaN(n) === true || text === "" || text === null) {
return text;
}
else {
for (i = 1; i <= n; i++) {
if (i > 1) {
text = encryptedString;
}
var evenChars = [];
var oddChars = [];
for (j = 0; j < text.length; j++) {
if (j % 2 === 0) {
evenChars.push(text.charAt(j));
}
else {
oddChars.push(text.charAt(j));
}
}
var encryptedString = oddChars.join("") + evenChars.join("");
}
return encryptedString;
}
}
function decrypt(encryptedText, n) {
if (n <= 0 || encryptedText === "" || encryptedText === null) {
return encryptedText;
}
else {
for (i = 1; i <= n; i++) {
if (i > 1) {
encryptedText = decryptedString;
}
var oddChars = [];
var evenChars = [];
for (j = 0; j < encryptedText.length; j++) {
if (j < Math.floor(encryptedText.length / 2)) {
oddChars.push(encryptedText.charAt(j));
}
else {
evenChars.push(encryptedText.charAt(j));
}
}
var convertedChars = []
for (k = 0; k < evenChars.length; k++) {
convertedChars.push(evenChars[k]);
convertedChars.push(oddChars[k]);
}
var decryptedString = convertedChars.join("");
}
return decryptedString;
}
}
document.getElementById("text").innerHTML = encrypt("maybe do i really", 1);
document.getElementById("text2").innerHTML = decrypt("ab oiralmyed ely", 1)
<p id="text"></p>
<p id="text2"></p>
Nothing wrong with the code itself. Basically HTML doesn't allow 2 or more spaces. You can use <pre> tag for the case like this.
document.getElementById("text").innerHTML = "<pre>" + encrypt("maybe do i really", 1) + "</pre>";

Palindrome function returns true when word isn't a palindrome

Could someone be kind enough to tell me why "almostomla" returns true in my code.
I have searched and have seen there are simpler versions but im so deep into this code now i need to make it work if at all possible.
Please excuse the terrible variable names, i was frustrated.
function palindrome(str) {
str = str.toLowerCase();
str = str.replace(/ /g, '').replace(/\./g, '').replace(/,/g, '');
for (var i = 0; i < str.length / 2; i++) {
for (var j = str.length - 1; j > str.length / 2 - 1; j--) {
var iDntKnow = str.charAt(i);
var iDntKnowEither = str.charAt(j);
if (iDntKnow === iDntKnowEither) {
return true;
} else {
return false;
}
}
}
}
Appreciate all answers.
While I can understand the frustration of wanting to make something work if you have put time into it, there is also something to be said for starting from the drawing board and not driving yourself crazy. The main problem I see with your code is that you have two loops when you only need one. The second loop is actually sabotaging you. I would suggest running a debugger (type "debugger" into your code and run) to see why.
I believe this is what you are trying to accomplish:
var palindrome = function(str) {
// Put any additional string preprocessing here.
for(var i = 0; i < str.length/2; i++) {
var j = str.length-i-1;
if (str[i] != str[j]) {
return false;
}
}
return true;
}
In this way you are comparing each mirrored element in the string to confirm if the string is a palindrome.
Your question seems to be answered by now.
If performance isn't an issue, why not just use this?
function palindrome(str) {
str = str.toLowerCase();
return (str.split().reverse().join() === str)
}
It splits the string into an array, reverses that and joins it back together. The result is compared to the original string.
You can only know if it's NOT a palindrome in each iteration.
Also, why using nested loops?
function palindrome(str) {
str = str.toLowerCase();
str = str.replace(/ /g, '').replace(/\./g, '').replace(/,/g, '');
for (var i = 0; i < str.length / 2; i++) {
if (str.charAt(i) !== str.charAt(str.length - i - 1)) {
return false;
}
}
return true;
}
This works:
function palindrome(string) {
string = string.toLowerCase();
for (var i = 0; i < Math.ceil(str.length/2); i++) {
var character1 = string.charAt(i);
var character2 = string.charAt(string.length-1-i);
if (character1 !== character2) {
return false;
}
}
return true;
}
Here is a version that omits spaces and commas:
var removeLetterFromString = function(string,letterPos){
var returnString = "";
for(var i = 0; i < string.length; i++){
if(i!==letterPos){
returnString=returnString+string.charAt(i);
}
}
return returnString;
};
var palindrome = function(string) {
string = string.toLowerCase();
var stringCheck="";
var recheck = true;
while(recheck){
recheck=false;
for(var i = 0; i < string.length; i ++){
if(string.charAt(i)===" "||string.charAt(i)===","){
string=removeLetterFromString(string,i);
}
}
for(var i = 0; i < string.length; i ++){
if(string.charAt(i)===" "||string.charAt(i)===","){
recheck=true;
}
}
}
if(string.length===0){
return false;
}
for (var i = 0; i < Math.ceil(string.length/2); i++) {
var j = string.length-1-i;
var character1 = string.charAt(i);
var character2 = string.charAt(j);
if (character1 !== character2) {
return false;
}
}
return true;
};

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