Count occurances in string from keyword array in javascript - javascript

I have an array:
var locations = ['Afghanistan','Albania','Algeria','New York'];
and a string:
var string = 'I love Afghanistan New York Afghanistan Andorra Andorra Algeria New York';
I want to count the number of times each keyword in the array appears in the string but can't figure out the best way to do that.

Here is my version:
function countItems(a, s) {
var x, i, output = {};
for (x = 0; x < a.length; x++) {
i = 0;
output[a[x]] = 0;
while ((i = s.indexOf(a[x], i)) > -1) {
output[a[x]]++;
i++
}
}
return output;
}
var result = countItems(locations, string);
// result['Albania'] === 0
Try it out here.

Try something like this. You could modify what you do with count -- store it in another array, display it (which is what this script does), etc.
var locations = ['Afghanistan','Albania','Algeria','New York'];
var str = 'I love Afghanistan New York Afghanistan Andorra Andorra Algeria New York';
for(var i=0; i<locations.length; i++) {
var pattern = new RegExp(locations[i], "g");
var m = str.match(pattern);
if (m != null)
{
var count = m.length; // the count
alert("There are " + count + " occurrences of " + locations[i]);
}
}

<script language="JavaScript">
var locations = ['Afghanistan','Albania','Algeria','New York'];
var string1 = 'I love Afghanistan New York Afghanistan Andorra Andorra Algeria New York';
for (var i=0;i<locations.length;i++) {
nCount = string1.split(locations[i]).length-1;
document.write(locations[i] + ' is found ' + nCount + ' times<br>');
}
</script>

This code only instantiates one RegExp object and uses a reverse while-loop. I'm pretty sure this is as fast as you can go without breaking the laws of physics :)
This is whats happening:
Construct regular expression string using a reverse while-loop
New up just one RegExp object, and match() it on the string
Count the length of the array returned by the match() function
Here's the implementation:
var countries = ["Afganistan", "America", "Island"];
var sentence = "I love Afganistan, America.. And I love America some more";
function countOccurrences(a, s)
{
var re = "",
l = a.length,
m;
while (l)
{
l--;
re += a[l];
if (l > 0) re += "|";
}
m = s.match(new RegExp(re, "gi")) || [];
return m.length;
}
Note: I am of course expecting the entries in the array to be sanitized for any special characters that will break the regular expression constructed within the function.
var occurrences = function countOccurrences(countries, sentence); // returns 3

Related

javascript replaces text on loop from separate strings

I made loop for, from split string and try to find some text and replace it by the result of separate string, here for example :
function replaceStr(str, find, replace) {
for (var i = 0; i < find.length; i++) {
str = str.replace(new RegExp(find[i], 'gi'), replace[i]);
}
return str;
}
var str = 'some text contain car and some house contain car, or car contain someone';
var values = "cat,dog,chicken";
splt = values.split(',');
for (i = 0; i < splt.length; i++) {
var find = ['car'];
var replace = ['' + values[i] + ''];
replaced = replaceStr(str, find, replace);
}
console.log(replaced);
//console.log(splt.length);
but the result return zeros
I want find all "car" text and replace it from splited text by comma characters
anyone can help me please..
hum what is the goal of your replaceStr function ?
maybe this is enough :
var str = 'some text contain car and some house contain car, or car contain someone';
var values = "cat,dog,chicken";
splt = values.split(',');
for (i = 0; i < splt.length; i++) {
var find = 'car';
str = str.replace(find, splt[i]);
}
console.log(str);
I guess implicitly from your question you want to replace "car" with cat, dog, chicken progressively to achieve this:
"some text contain cat and some house contain dog, or chicken contain someone"
So roughly this would be your solution:
var str = 'some text contain car and some house contain car, or car contain someone';
var values = "cat,dog,chicken";
var splt = values.split(',');
var replaced = str;
for (i = 0; i < splt.length; i++) {
replaced = replaced.replace('car', splt[i]);
}
console.log(replaced);

javascript replace random letters with underscore

I want to write this google spreadsheet javascript code to replace random letters in a string.
I have created a code that does it but not randomly, plus it also replaces the spaces with an underscore (which is problematic).
The end result I'm interested in is to go from this (the sentences are in French btw.):
'J’habite à New York.'
to this:
'_’h_b_t_ à _ew _or_.'
Let's say that given a sentences, at least half of the number of letters must be replaced with an underscore.
Thank you for your help. (ps: i'm not a programmer)
The code I have so far:
var v = [['J’habite à New York.', 'Sì', ], ['Je m’appelle John. !']];
for (var r in v){
for (var c in v[r]){
var d = v[r][c];
var l = d.length;
var u = l;
while(u > 0){
var res = d.replace(d[u-2], '_');
d = res;
u = u - 2;
}
console.log(res);
}
}
You might try something like this :)
var a = "Text i want to replace text from";
var splitted = a.split('');
var count = 0; // variable where i keep trace of how many _ i have inserted
while(count < a.length/2) {
var index = Math.floor(Math.random()*a.length); //generate new index
if(splitted[index] !== '_' && splitted[index] !== ' ') {
splitted[index] = '_';
count++;
}
}
var newstring = splitted.join(""); //the new string with spaces replaced
EDIT: i tried it now on console and seems to be working. What problem does it give to you?
2° EDIT: you could do:
splitted[index] = ' _ ';
instead of
splitted[index] = '_';
also notice that i changed the if condition from:
if(splitted[index] !== '_')
to
if(splitted[index] !== '_' && splitted[index] !== ' ')
to avoid replacing empty spaces with '_'
:)
You are overcomplicatig a bit. Just turn the string into an array of characters, then map it to an array of characters with some letters replaced and turn it back into a string.
function replace(str) {
return str.split("").map(char => Math.random() > 0.5 ? "_" : char).join("");
}
var v = [
['J’habite à New York.', 'Sì', ],
['Je m’appelle John. !', 'Non!',]
];
for (const pair of v) {
pair[0] = replace(pair[0]);
pair[1] = replace(pair[1]);
}
console.log(v)

Test for multiple words in a string

I have a string like so:
var str = "FacebookExternalHit and some other gibberish";
Now I have a list of strings to test if they exist in str. Here they are in array format:
var bots = ["FacebookExternalHit", "LinkedInBot", "TwitterBot", "Baiduspider"];
What is the fastest and/or shortest method to search str and see if any of the bots values are present? Regex is fine if that's the best method.
Using join you can do:
var m = str.match( new RegExp("\\b(" + bots.join('|') + ")\\b", "ig") );
//=> ["FacebookExternalHit"]
I don't know that regex is necessarily the way to go here. Check out Array.prototype.some()
var str = "FacebookExternalHit and some other gibberish";
var bots = ["FacebookExternalHit", "LinkedInBot", "TwitterBot", "Baiduspider"];
var isBot = bots.some(function(botName) {
return str.indexOf(botName) !== -1;
});
console.log("isBot: %o", isBot);
A regular for loop is even faster:
var str = "FacebookExternalHit and some other gibberish";
var bots = ["FacebookExternalHit", "LinkedInBot", "TwitterBot", "Baiduspider"];
var isBot = false;
for (var i = 0, ln = bots.length; i < ln; i++) {
if (str.indexOf(bots[i]) !== -1) {
isBot = true;
break;
}
}
console.log("isBot: %o", isBot);

Why does my Javascript trim Function not work?

I am using this function to build a pig latin translator and seem to have everything figured out except for the .trim() part. What should I do different?
function ParseText()
{
var myText = "asdf\n hat\n cat dog\n apple";
var lines = myText.split("\n");
var results = "";
for (var i = 0, len = lines.length; i < len; i++) {
lines[i].trim();
var words = lines[i].split(" ");
for (var j = 0, lenght = words.length; j < lenght; j++) {
var word = words[j];
if (word.charAt(0) == "a" || word.charAt(0) == "e" || word.charAt(0) == "i" || word.charAt(0) == "o" || word.charAt(0) == "u" || word.charAt(0) == "y")
{
results = results + word + "ay ";
}else {
var mutated = word.substring(1, word.length);
mutated = mutated + word.charAt(0)+ "ay ";
results = results + mutated;
}
}
results = results + "\n";
}
return results;
}
On the line lines[i].trim(); nothing seems to happen. the whitespace still becomes a \n item in the split array.
What should I change to remove the whitespace?
lines[i].trim(); does NOT modify the current string (see the doc here). It returns a new string.
If you want to trim the current string, then you need to do this:
lines[i] = lines[i].trim();
As per comments, here's very basic version of pig latin using regex that works with lowercase strings but it can be adjusted to handle mixed lower and upper case:
function pigLatin(str) {
return str
.toLowerCase() // make sure string is lowercase
.replace(/\b[aeiuo]\w+\b/g, '$&way') // starts with vowel
.replace(/\b([^aeiou\s])(\w+)\b/g, '$2$1ay'); // starts with consonant
}
// Example:
var str = 'hello world egg plant yellow';
console.log(pigLatin(str)); //=> "ellohay orldway eggway lantpay ellowyay"

Testing for a common word between 2 strings in javascript

I have to match 2 strings where at least one word is same, I need to give a success msg.
var str1 = "Hello World";
var str2 = "world is beautiful";
I need to match/compare these 2 strings, in both strings world is matching, So i need to print a success message. How do I go about it.
The following code will output all the matching words in the both strings:
var words1 = str1.split(/\s+/g),
words2 = str2.split(/\s+/g),
i,
j;
for (i = 0; i < words1.length; i++) {
for (j = 0; j < words2.length; j++) {
if (words1[i].toLowerCase() == words2[j].toLowerCase()) {
console.log('word '+words1[i]+' was found in both strings');
}
}
}
You can avoid comparing all the words in one list with all the words in the other by sorting each and eliminating duplicates. Adapting bjornd's answer:
var words1 = str1.split(/\s+/g),
words2 = str2.split(/\s+/g);
var allwords = {};
// set 1 for all words in words1
for(var wordid=0; wordid < words1.length; ++wordid) {
var low = words1[wordid].toLowerCase();
allwords[low] = 1;
}
// add 2 for all words in words2
for(var wordid=0; wordid < words2.length; ++wordid) {
var current = 0;
var low = words2[wordid].toLowerCase();
if(allwords.hasOwnProperty(low)) {
if(allwords[low] > 1) {
continue;
}
}
current += 2;
allwords[low] = current;
}
// now those seen in both lists have value 3, the rest either 1 or 2.
// this is effectively a bitmask where the unit bit indicates words1 membership
// and the 2 bit indicates words2 membership
var both = [];
for(var prop in allwords) {
if(allwords.hasOwnProperty(prop) && (allwords[prop] == 3)) {
both.push(prop);
}
}
This version should be reasonably efficient, because we are using a dictionary/hash structure to store information about each set of words. The whole thing is O(n) in javascript expressions, but inevitably dictionary insertion is not, so expect something like O(n log n) in practise. If you only care that a single word matches, you can quit early in the second for loop; the code as-is will find all matches.
This is broadly equivalent to sorting both lists, reducing each to unique words, and then looking for pairs in both lists. In C++ etc you would do it via two sets, as you could do it without using a dictionary and the comparison would be O(n) after the sorts. In Python because it's easy to read:
words1 = set(item.lower() for item in str1.split())
words2 = set(item.lower() for item in str2.split())
common = words1 & words2
The sort here (as with any set) happens on insertion into the set O(n log n) on word count n, and the intersection (&) is then efficent O(m) on the set length m.
I just tried this on WriteCodeOnline and it works there:
var s1 = "hello world, this is me";
var s2 = "I am tired of this world and I want to get off";
var s1s2 = s1 + ";" + s2;
var captures = /\b(\w+)\b.*;.*\b\1\b/i.exec(s1s2);
if (captures[1])
{
document.write(captures[1] + " occurs in both strings");
}
else
{
document.write("no match in both strings");
}
Just adapting #Phil H's code with a real bitmask:
var strings = ["Hello World", "world is beautiful"]; // up to 32 word lists
var occurrences = {},
result = [];
for (var i=0; i<strings.length; i++) {
var words = strings[i].toLowerCase().split(/\s+/),
bit = 1<<i;
for (var j=0, l=words.length; j<l; j++) {
var word = words[j];
if (word in occurrences)
occurrences[word] |= bit;
else
occurrences[word] = bit;
}
}
// now lets do a match for all words which are both in strings[0] and strings[1]
var filter = 3; // 1<<0 | 1<<1
for (var word in occurrences)
if ((occurrences[word] & filter) === filter)
result.push(word);
OK, the simple way:
function isMatching(a, b)
{
return new RegExp("\\b(" + a.match(/\w+/g).join('|') + ")\\b", "gi").test(b);
}
isMatching("in", "pin"); // false
isMatching("Everything is beautiful, in its own way", "Every little thing she does is magic"); // true
isMatching("Hello World", "world is beautiful"); // true
...understand?
I basically converted "Hello, World!" to the regular expression /\b(Hello|World)\b/gi
Something like this would also do:
isMatching = function(str1, str2) {
str2 = str2.toLowerCase();
for (var i = 0, words = str1.toLowerCase().match(/\w+/g); i < words.length; i++) {
if (str2.search(words[i]) > -1) return true;
}
return false;
};
var str1 = "Hello World";
var str2 = "world is beautiful";
isMatching(str1, str2); // returns true
isMatching(str1, 'lorem ipsum'); // returns false

Categories

Resources