Find white space in a string back from an index position - javascript

Lets say I have a string, but the text could be anything!
This is a test case
The 'boundary' is the count after a space, this means the charIndex =
(0) This
(5) is
(8) a
(10) test
(15) case
The above means from (0) to (5) the word equals 'this '.
If I wanted to know the word just used, I would need to substr start at charIndex and look backwards until indexOf(' ')
Example: If I wanted to find the word just used at charIndex (10) how would I instruct javascript to look backwards until the next space and give me the word "a ".
Is it possible to do this, with as little process time, using Javascript, or JQuery?
UPDATE
Instead of looking after the word and going back, I decided to achieve what I needed, I split the words and used each charIndex as a count. Code follows:
var u = new SpeechSynthesisUtterance();
var words = element.innerHTML.split(' ');
var a = 0;
u.text = element.innerHTML;
u.lang = 'en-UK';
u.rate = 0.7;
u.onboundary = function(event) {
console.log(words);
element.innerHTML = element.innerHTML.replace(words[a], '<strong>' + words[a] + '</strong>');
a++;
}
But as this is not the questions answer, still the best answer to reverse search a string is that which is marked correct, although it still needs some work depending on the string structure.

Not clear about exact question but you can use a combination of lastindexof, indexof and substr in your case or write your own stuff.
Note: No error handling etc. is being done. Please do that.
var stringToBeParsed="This is a test case"
i = stringToBeParsed.lastIndexOf(" ",8);
j = stringToBeParsed.indexOf(" ",i+1);
document.getElementById('output').innerText = stringToBeParsed.substr(i,j-i);
Custom
function parseBackward(stringToBeParsed, indexOfSpace){
var output = '';
for (var i = indexOfSpace-1; i >= 0; i--) {
if(stringToBeParsed.charAt(i) == ' '){
break;
}
output = stringToBeParsed.charAt(i) + output;
}
document.getElementById('output').innerText = output;
}

If I understand your question you can use lastIndexOf:
var TC="This is a test case"
TC.lastIndexOf(" ",10)
This will return 9, using lastIndexOf(string,position) searches backwards.
EDIT:
If you need the word:
var TC="This is a test case"
TC.substr(TC.lastIndexOf(' ',10)+1,TC.length - TC.indexOf(' ',10));
So you use substr. First search backwards from position 10 space (and sum 1 to get on the beginning of letter) to start the substr. As second parameter y get the next occurrence and substract to length.
EDIT2:
Ok this functions works is supposed to work in less than milisecond:
function getWord(phrase,position){
var last = phrase.indexOf(' ',position);
var more=0
if (last == -1){
more = phrase.length;
} else { more = phrase.indexOf(' ',position);}
var word = phrase.substring(phrase.lastIndexOf(' ',position)+1,more);
return(word);
}
In this plunkr http://plnkr.co/wfeitWvSvoLzqIknKFyg you can check how it takes less than a milisecond to work. And if you open a console you will see how it take the word at position specified.

Related

How to print all characters by their index in JavaScript?

Just for exercising with indexOf() method and to have a better familiarity with how it works and what can be done with it, I desire to print the index for each character in a phrase, one by one.
I could do it successfully manually, this way:
// Print index for char of phrase (case insensitive):
let phrase = "ab";
alert(phrase.indexOf("a")); // 0
alert(phrase.indexOf("b")); // 1
alert(phrase.indexOf("z")); // -1
But when I tried to use a loop, I failed:
// Print char by index:
let phrase = "ab";
for (let i = -1; i < phrase.indexOf(); i++) {
alert(phrase.length[i]);
}
I also tried with regex to target each character inside phrase but also failed:
let phrase = "ab";
for (let i = -1; i < phrase.indexOf(/./); i++) {
alert(phrase.length[i]);
}
To clarify, my aim is to have a first alert with 0, and the second with 1. I just want to print the index of each character, instead the character length, as can easily be done with:
phrase.length // 2.
How could I print the index of each character in separate alerts?
It is super important for me to use indexOf() inside a loop to know this syntax.
You could do it this way :
for(let i=0; i<phrase.length; i++) {
console.log(phrase.indexOf(phrase[i]));
}
Don't use indexOf. You use this method to get the position (index) of a certain character in the string:
A string has a length property and can be iterated:
let phrase = "aaabbbaaaabbb"
function getAllIndices(stringInput) {
for (let i = 0; i < stringInput.length; i++) {
//you simply need to output i.
console.log(stringInput[i] + " > " + i);
}
}
getAllIndices(phrase);
While not always the case: the most common format for a for loop is:
for (let i = 0; i < someVariable.length; i++) { //...some code }
And indeed that's what you want here.
It means:
start at i being 0 (i = 0)
Do whatever is in my body (// ...some code)
increase i by 1 (i++)
Repeat, until i is equal to one less than the length of someVariable (someVariable.length) *
* That last step may seem kinda confusing. Remember: indices start at 0, but length count, well, counts normal - so starting at 1. So an string of length 3, say 'c'+'a'+'t'. is made up of characters at indices [0, 1, 2]. Sooo you want the loop, to stop at that last index - 2 - which is (always) one less that the length. (But honestly, this is overexplaining it. The short answer is: if you wanna loop through something - 99 times out of 100 you want that exact for loop format given up top.
So to look at your example: we wanna fix three things:
We want to have let i = 0; (remember it doesn't increment until it's run once
We want to say i < phrase.length; (i < phrase.indexOf() doesn't mean anything. phrase.indexOf() is a function, not a number.)
phrase.length means "tell me the length of the variable phrase." It just returns a number. (So phrase.length[i] doesn't mean anything). If you want to alert whatever letter is at this index, it's just phrase[i]. *
* If this syntax for getting a letter by just putting [#] after strings seems weird - well that's because it was more designed for arrays . If you have let arr = ['a', 'b', 'c'], then sure, I could see why the JavaScript devs said "let's make a quick way to get, oh, the value at index 2 of an array. How about just arr[2]? But for consistency, they said "yeah sure, let's give this ability to strings to." And if you think about it, a string is sort of just an array of letters.
Update: I just noticed you wanted the index of each letter, not the letter itselt. Well...technically you could just alert(i) then. That's it, that's the index. But if you wanted to know what letter we're talking about, I would do something like alert("Letter " + phrase[i] + " is at index " + i)
So our final answer is:
let phrase = "ab";
for (let i = 0; i < phrase.length; i++) {
alert("Letter " + phrase[i] + " is at index " + i)
}
It is super important for me to use indexOf() inside a loop to know this syntax.
You would never use indexOf() for something like this. It would not just be unnecessary, it would be wrong. If you had the string banana and tried to use indexOf() to (re)check each letters position, you would get 0,1,2,1,2,1. Why? Because indexOf() only returns the index of the first instance of that letter.
indexOf() is not something you'd likely pair with a for loop - at least not a for loop searching the same string. It is a loop itself. It's job is to prevent you from having to write a for loop to find the index of "b" in "ab". It will do it for you.
To print the index of each character in a loop you don't need indexOf()
let phrase = "ab";
for (let i = 0; i < phrase.length; i++) {
alert (i);
}
because i is the exact index you need.
In fact if you use indexOf() in a loop, that's what it looks like :
let phrase = "ab";
for (let i = 0; i < phrase.length; i++) {
alert (phrase.indexOf (phrase[i]));
}
Same result as before, but this time, instead of displaying i, you retrieve the current element in phrase and use indexOf() to get the already known index.
EDIT : indexOf() in this case work as expected because letters in phrase are different. But as SamVK said if let phrase = "banana";, it can't work because it will return always 1 for letter 'a' so you must not use it for that kind of loop.
I did not use let i = -1 because it is not an index of phrase. It is just what indexOf() returns if it can't find the element given.
I hope it helps.
If you absolutely want to use indexOf in a loop, you could do so :
let phrase = "ab";
Array.from(phrase).forEach(char => {
console.log(phrase.indexOf(char))
})
But this is pretty useless as there are simpler ways to accomplish this but since it looks like it is for a learning purpose, I hope this answer helps you!

Checking if combination of any amount of strings exists

I'm solving a puzzle and I have an idea of how to solve this problem, but I would like some guidance and hints.
Suppose I have the following, Given n amount of words to input, and m amount of word combos without spaces, I will have some functionality as the following.
4
this
is
my
dog
5
thisis // outputs 1
thisisacat // 0, since a or cat wasnt in the four words
thisisaduck // 0, no a or cat
thisismy // 1 this,is,my is amoung the four words
thisismydog // 1
My thoughts
First What I was thinking of doing is storing those first words into an array. After that, I check if any of those words is the first word of those 5 words
Example: check if this is in the first word thisis. It is! Great, now remove that this, from thisis to get simply just is, now delete the original string that corresponded to that equality and keep iterating over the left overs (now is,my,dog are available). If we can keep doing this process, until we get an empty string. We return 1, else return 0!
Are my thoughts on the right track? I think this would be a good approach (By the way I would like to implement this in javascript)
Sorting words from long to short may in some cases help to find a solution quicker, but it is not a guarantee. Sentences that contain the longest word might only have a solution if that longest word is not used.
Take for instance this test case:
Words: toolbox, stool, boxer
Sentence: stoolboxer
If "toolbox" is taken as a word in that sentence, then the remaining characters cannot be matched with other valid words. Yet, there is a solution, but only if the word "toolbox" is not used.
Solution with a Regular Expression
When regular expressions are allowed as part of the solution, then it is quite simple. For the above example, the regular expression would be:
^(toolbox|stool|boxer)*$
If a sentence matches that expression, it is a solution. If not, then not. This is quite straightforward, and doesn't really require an algorithm. All is done by the regular expression interpreter. Here is a snippet:
var words = ['this','is','a','string'];
var sentences = ['thisis','thisisastring','thisisaduck','thisisastringg','stringg'];
var regex = new RegExp('^(' + words.join('|') + ')*$');
sentences.forEach(sentence => {
// search returns a position. It should be 0:
console.log(sentence + ': ' + (sentence.search(regex) ? 'No' : 'Yes'));
});
But using regular expressions in an algorithm-challenge feels like cheating: you don't really write the algorithm, but rely on the regular expression implementation to do the job for you.
Without Regular Expressions
You could use this algorithm: first check whether a word matches at the start of the input sentence, and if so, remove that first occurrence from it. Then repeat this for the remaining part of the sentence. If this can be repeated until no characters are left over, you have a solution.
If characters are left over which cannot be matched with any word... well, then you cannot really conclude there is no solution for that sentence. It might be that some earlier made word choice was the wrong one, and there was an alternative. So to cope with that, your algorithm could backtrack and try other words.
This principle can be implemented through recursion. To gain memory-efficiency, you could leave the original sentence in-tact, and work with an index in that sentence instead.
The algorithm is implemented in arrow-function testString:
var words = ['this','is','a','string'];
var sentences = ['thisis','thisisastring','thisisaduck','thisisastringg','stringg'];
var testString = (words, str, i = 0) =>
i >= str.length || words.some( word =>
str.substr(i, word.length) == word && testString(words, str, i + word.length)
);
sentences.forEach(sentence => {
console.log(sentence + ': ' + (testString(words, sentence) ? 'Yes' : 'No'));
});
Or, the same in non-arrow-function syntax:
var words = ['this','is','a','string'];
var sentences = ['thisis','thisisastring','thisisaduck','thisisastringg','stringg'];
var testString = function (words, str, i = 0) {
return i >= str.length || words.some(function (word) {
return str.substr(i, word.length) == word
&& testString(words, str, i + word.length);
});
}
sentences.forEach(function (sentence) {
console.log(sentence + ': ' + (testString(words, sentence) ? 'Yes' : 'No'));
});
... and without some(), forEach() or ternary operator:
var words = ['this','is','a','string'];
var sentences = ['thisis','thisisastring','thisisaduck','thisisastringg','stringg'];
function testString (words, str, i = 0) {
if (i >= str.length) return true;
for (var k = 0; k < words.length; k++) {
var word = words[k];
if (str.substr(i, word.length) == word
&& testString(words, str, i + word.length)) {
return true;
}
}
}
for (var n = 0; n < sentences.length; n++) {
var sentence = sentences[n];
if (testString(words, sentence)) {
console.log(sentence + ': Yes');
} else {
console.log(sentence + ': No');
}
}
Take the 4 words, put them into a regex.
Use that regex to split each string.
Take the length of the resulting array (subtract one for the initial length of one).
var size = 'thisis'.split(/this|is|my|dog/).length - 1
Or if your list of words is an array
var search = new RegExp(words.join('|'))
var size = 'thisis'.split(search).length - 1
Either way you are splitting up the string by the list of words you have defined.
You can sort the words by length to ensure that larger words are matched first by
words.sort(function (a, b) { return b.length - a.length })
Here is the solution for anyone interested
var input = ['this','is','a','string']; // This will work for any input, but this is a test case
var orderedInput = input.sort(function(a,b){
return b.length - a.length;
});
var inputRegex = new RegExp(orderedInput.join('|'));
// our combonation of words can be any size in an array, just doin this since prompt in js is spammy
var testStrings = ['thisis','thisisastring','thisisaduck','thisisastringg','stringg'];
var foundCombos = (regex,str) => !str.split(regex).filter(str => str.length).length;
var finalResult = testStrings.reduce((all,str)=>{
all[str] = foundCombos(inputRegex,str);
if (all[str] === true){
all[str] = 1;
}
else{
all[str] = 0;
}
return all;
},{});
console.log(finalResult);

having an issue w/ .split in a JavaScript function that gets the max # of repeating chars per word in a string

I'm writing a JavaScript function that has to take in a string argument & determine the word or words with the maximum number or repeated (or most frequent) non sequential characters and return that word or words.
The way that I went about solving this problem was to first find the maximum number of times a character was repeated per word and record that number to use later in a function to test against every word in the string (or the array of strings as I later split it); if the word met the conditions, it's pushed into an array that I return.
My maxCount function seemed to work fine on its own but when I try to make it work together with my other function to get the words with max repeated chars returned, it's not working in JS Fiddle - it keeps telling me that "string.split is not a function" - I'll admit that the way I'm using it (string.split(string[i]).length) to analyze words in the string letter by letter is a bit unconventional - I hope there's some way to salvage some of my logic to make this work in the functions that can work together to get the results that I want.
Also, I don't know if I'm using Math.max correctly/in a "legal" way, I hope so. I've tried switching my variable name to "string" thinking that would make a difference but it did not even though my arguments are of the string variety and it's a string that's being represented.
Here's a link to my Fiddle:
https://jsfiddle.net/Tamara6666/rdwxqoh6/
Here's my code:
var maxCount = function (word) {
/// var maxRepeats = 0;
var numArray = [];
var string = word;
for (var i = 0, len = string.length; i < len; i++) {
//split the word('string') into letters at the index of i
numArray.push((string.split(string[i]).length) -1);
}
var max = Math.max(...numArray);
return max;
}
///console.log(maxCount("xxxxxxxxxxxxx"));
var LetterCount = function(string){
var repeatedChars = 0;
var wordArray=[];
var stringArray = string.split(" ");
for (var i = 0; i < stringArray.length; i++){
var eachWord = stringArray[i];
var maxRepeats = maxCount(stringArray);
if (repeatedChars < maxRepeats) {
repeatedChars = maxRepeats;
wordArray = [eachWord];
}else if (repeatedChars == maxRepeats) {
wordArray.push(eachWord);
}
}
return wordArray;
};
console.log(LetterCount("I attribute my success to cats"));
//should return ["attribute", "success"]
*** I've tried to map this first function onto the array formed when I split my string at the spaces but it is just returned me an empty array (I also might not have been using map correctly in this example); I also have tried using valueOf to extract the primitive value out of the array from the first function which also didn't work. I'm not really sure what to do at this point or what angle to take- I feel if I understood more what was going wrong I could more easily go about fixing it. Any help would be much appreciated. Thanks!
You are passing an array to maxCount at line 20, while it expects a string:
var maxRepeats = maxCount(stringArray);
You should use:
var maxRepeats = maxCount(eachWord);
If you are getting split is not a function error then first make sure that your string isn't null by printing it on console. If it isn't null then confirm that its a string not an array or some other thing.

How do I fix this palindrome checker?

I have tried to make this palindrome checker but it sometimes returns the right answer and sometimes not. Please tell me the bugs in this code... I know that there are more efficient ways to make a palindrome checker but for learning purposes I want to know what is wrong with mine...
function palindrome(str) {
var newString;
//convert string to lower-case
var strLowerCase = str.toLowerCase();
//Find string length
var strLength = str.length;
//replace first 1/2 with second 1/2
newString = replaceLetters(strLowerCase,strLength);
if(newString === strLowerCase){
return true;
}else{
return false;
}
}
function replaceLetters(string,length){
var x;
for(var a = 0; a<Math.ceil(length/2) ; a++){
x = string.replace(string.charAt(a),string.charAt(length-1));
length--;
}
return x;
}
palindrome("eye");
You shouldn't pass the str length as a parameter. Just make a variable length from str.length - 1 in replaceLetters. Also you want math.floor not math.ceil. let's say for a 9 letter words, you only want to swap the first 4 chars not the first 5. You don't need to swap the middle char which is the 5th.Ex: Racecar, you don't swap e with anything to check if its palindrome. You can also use the splice function instead of making your own replace letters function. Some other knitpicking, what's the point of making the strlowercase var since your only calling to lowercase() once?

Regex, grab only one instance of each letter

I have a paragraph that's broken up into an array, split at the periods. I'd like to perform a regex on index[i], replacing it's contents with one instance of each letter that index[i]'s string value has.
So; index[i]:"This is a sentence" would return --> index[i]:"thisaenc"
I read this thread. But i'm not sure if that's what i'm looking for.
Not sure how to do this in regex, but here's a very simple function to do it without using regex:
function charsInString(input) {
var output='';
for(var pos=0; pos<input.length; pos++) {
char=input.charAt(pos).toLowerCase();
if(output.indexOf(char) == -1 && char != ' ') {output+=char;}
}
return output;
}
alert(charsInString('This is a sentence'));
As I'm pretty sure what you need cannot be achieved using a single regular expression, I offer a more general solution:
// collapseSentences(ary) will collapse each sentence in ary
// into a string containing its constituent chars
// #param {Array} the array of strings to collapse
// #return {Array} the collapsed sentences
function collapseSentences(ary){
var result=[];
ary.forEach(function(line){
var tmp={};
line.toLowerCase().split('').forEach(function(c){
if(c >= 'a' && c <= 'z') {
tmp[c]++;
}
});
result.push(Object.keys(tmp).join(''));
});
return result;
}
which should do what you want except that the order of characters in each sentence cannot be guaranteed to be preserved, though in most cases it is.
Given:
var index=['This is a sentence','This is a test','this is another test'],
result=collapseSentences(index);
result contains:
["thisaenc","thisae", "thisanoer"]
(\w)(?<!.*?\1)
This yields a match for each of the right characters, but as if you were reading right-to-left instead.
This finds a word character, then looks ahead for the character just matched.
Nevermind, i managed:
justC = "";
if (color[i+1].match(/A/g)) {justC += " L_A";}
if (color[i+1].match(/B/g)) {justC += " L_B";}
if (color[i+1].match(/C/g)) {justC += " L_C";}
if (color[i+1].match(/D/g)) {justC += " L_D";}
if (color[i+1].match(/E/g)) {justC += " L_E";}
else {color[i+1] = "L_F";}
It's not exactly what my question may have lead to belive is what i wanted, but the printout for this is what i was after, for use in a class: <span class="L_A L_C L_E"></span>
How about:
var re = /(.)((.*?)\1)/g;
var str = 'This is a sentence';
x = str.toLowerCase();
x = x.replace(/ /g, '');
while(x.match(re)) {
x=x.replace(re, '$1$3');
}
I don't think this can be done in one fell regex swoop. You are going to need to use a loop.
While my example was not written in your language of choice, it doesn't seem to use any regex features not present in javascript.
perl -e '$foo="This is a sentence"; while ($foo =~ s/((.).*?)\2/$1/ig) { print "<$1><$2><$foo>\n"; } print "$foo\n";'
Producing:
This aenc

Categories