I have the following textarea code.
<textarea id="message" name="message"></textarea>
I need to get the value of the textarea and track the message content and extract out keywords that is hashed (#).
Example if the message is as below
This is my message #message #lol #haha
When i click on submit button. The keywords that i should get is 'lol and 'haha' and 'message'.
I am using jquery. Can anyone give me some advices on how to go about doing so?
As per comment, split at whitespaces, then uses Array.prototype.reduce by checking first character.
Javascript
var message = "This is my message #message #lol #haha";
var wanted = message.split(/\s/).reduce(function (previous, word) {
if (word.charAt(0) === "#") {
previous.push(word.slice(1));
}
return previous;
}, []).join(" ");
console.log(wanted);
Output
message lol haha
On jsfiddle
Alternatively using Array.prototype.filter and Array.prototype.map
Javascript
var message = "This is my message #message #lol #haha";
var wanted = message.split(/\s/).filter(function (word) {
return word.charAt(0) === "#";
}).map(function (word) {
return word.slice(1);
}).join(" ");
console.log(wanted);
On jsfiddle
Note: all of the above Array methods require a shim on pre ECMA5 browsers, available on their respective MDN pages or the use of es5_shim
Other alternatives, if you so desired, would be to use Array.prototype.forEach (which would require a shim), for or while to perform the looping of elements and Array.prototype.slice and Array.prototype.push the relevant ones.
Use a RegExp like /(?:\s|^)#([^\s]+)/g with String.prototype.match, i.e. space or start of line, then #, then non-space.
var m = 'This is my message #message #lol #haha'.match(/(?:\s|^)#([^\s]+)/g);
// [" #message", " #lol", " #haha"]
Then you can loop over these with your preferred loop, e.g. with for
var i, found = [], u;
for (var i = 0; i < m.length; ++i) {
u = m[i];
if (u.charAt(1) === '#') u = u.slice(2);
else u = u.slice(1);
found.push(u);
}
found; // ["message", "lol", "haha"]
With the same RegExp, because of how I set up the capture groups, you can strip and catch at the same time using String.prototype.replace.
var found = [], str = 'This is my message #message #lol #haha';
str = str.replace(
/(?:\s|^)#([^\s]+)/g,
function (m, keyword) {
found.push(keyword);
return '';
}
);
str; // "This is my message"
found; // ["message", "lol", "haha"]
A slight modification here could also let you capture them using replace without removing them, (return m in the function or just keep another copy of the string).
var str = "This is my message #message #lol #haha";
// or var str = $('#message').val();
var words = str.split(' ');
words = $(words).map(function (i,v) {
if(v.indexOf('#') === 0)return v.replace("#",'');
}).get();
console.log(words);
//output `==>` ["message", "lol", "haha"]
Demo ---> http://jsfiddle.net/vTpSk/2/
// You split the words with the space
var arrayContainingEveryWords = $("#message").val().split(" ");
var desiredWords = [];
// For each word within the text area
for (var i = 0; i < arrayContainingEveryWords.length; i++)
{
var word = arrayContainingEveryWords[i];
// If the first letter of the word is a #
if (word.charAt(0) == "#")
{
// Add the word (minus the #) to an array
desiredWords.push(word.slice(1));
}
}
console.log(desiredWords);
You can use one simple regular expression: \B#\w+.
var keywords = 'This is my message #message #lol #haha'.match(/\B#\w+/g);
And then remove the #s if need be:
keywords = keywords.map(function(k) { return k.substring(1); });
// or jQuery, for compatibility:
keywords = $.map(keywords, function() { return this.substring(1); });
Or use a loop:
var keywords = [];
var keyword;
var re = /\B#(\w+)/g;
while(keyword = re.exec('This is my message #message #lol #haha')) {
keywords.push(keyword[1]);
}
Use .split('#') on the string to get an array of words, then use .trim() on each item to get rid of the space.
Related
I'm trying to make a function that finds the string that contains all words from an array.
I have tried this:
function multiSearchOr(text, searchWords){
var searchExp = new RegExp(searchWords.join("|"),"gi");
return (searchExp.test(text))?"Found!":"Not found!";
}
alert(multiSearchOr("Hello my name sam", ["Hello", "is"]))
But this only alert "Found" when one of the words have been found.
I need it to alert me when all the words are in the string.
An example:
var sentence = "I love cake"
var words = ["I", "cake"];
I want the application to alert me when it finds all of the words from the array in the string sentence. Not when it only found one of the words.
If you're interested in using only a single regular expression, then you need to use a positive lookahead when constructing your expression. It will look something like that:
'(?=\\b' + word + '\\b)'
Given this construction, you can then create your regular expression and test for the match:
function multiSearchOr(text, searchWords){
var regex = searchWords
.map(word => "(?=.*\\b" + word + "\\b)")
.join('');
var searchExp = new RegExp(regex, "gi");
return (searchExp.test(text))? "Found!" : "Not found!";
}
Here's a working example. You simply need to iterate over the array and compare if the words are present in the string or not using indexOf(). if it is not equal then alert Not found otherwise alert Found.
function multiSearchOr(text, searchWords){
for(var i=0; i<searchWords.length; i++)
{
if(text.indexOf(searchWords[i]) == -1)
return('Not Found!');
}
return('Found!');
}
alert(multiSearchOr("Hello my name sam", ["Hello", "is"]));
Is this what are you looking for ? In this way, you can use more complex sentences that contain non-alphanumeric characters.
var sentence = "Hello, how are you ?"
var test1 = ["Hello", "how", "test"];
var test2 = ["hello", "How"];
function multiSearchOr(text, searchWords){
if (text && searchWords) {
var filteredText = text.match(/[^_\W]+/g);
if (filteredText !== null) {
var lowerCaseText = filteredText.map(function(word) {
return word.toLowerCase();
});
for (var i = 0; i < searchWords.length; i++) {
if (lowerCaseText.indexOf(searchWords[i].toLowerCase()) === -1) {
return "Not found!";
}
}
return "Found!"
}
return "Error: the text provided doesn't contain any words!"
}
return "Error: Props are missing";
}
console.log(multiSearchOr(sentence, test1));
console.log(multiSearchOr(sentence, test2));
if all(word in text for word in searchWords):
print('found all')
if any(word in text for word in searchWords):
print('found at least one')
all() if you want that all the word in the list searchWords are in the text
any() if it's enough that one list word is in the text
Here is a version that will split the sentense you pass and check each word
const matchAllEntries = (arr, target) => target.every(v => arr.includes(v));
const arr = ['lorem', 'ipsum', 'dolor'];
const strs = ['lorem blue dolor sky ipsum', 'sky loremdoloripsum blue', 'lorem dolor ipsum'];
strs.forEach(str => {
// split on non alphabet and numbers (includes whitespace and puntuation)
parts = str.split(/\W/);
console.log(matchAllEntries(arr, parts));
})
I'm facing some problem while trying to send text to some spelling API.
The API return the corrections based on the words index, for example:
sentence:
"hello hoow are youu"
So the API index the words by numbers like that and return the correction based on that index:
0 1 2 3
hello hoow are youu
API Response that tell me which words to correct:
1: how
3: you
On the code I using split command to break the sentence into words array so I will be able to replace the misspelled words by their index.
string.split(" ");
My problem is that the API trim multiple spaces between words into one space, and by doing that the API words index not match my index. (I would like to preserve the spaces on the final output)
Example of the problem, sentence with 4 spaces between words:
Hello howw are youu?
0 1 2 3 4 5 6 7
hello hoow are youu
I thought about looping the words array and determine if the element is word or space and then create something new array like that:
indexed_words[0] = hello
indexed_words[0_1] = space
indexed_words[0_2] = space
indexed_words[0_3] = space
indexed_words[0_4] = space
indexed_words[0_5] = space
indexed_words[0_6] = space
indexed_words[0_7] = space
indexed_words[1] = how
indexed_words[2] = are
indexed_words[3] = you?
That way I could replace the misspelled words easily and than rebuild the sentence back with join command but the problem but the problem that I cannot use non-numeric indexes (its mixed up the order of the array)
Any idea how I can keep the formatting (spaces) but still correct the words?
Thanks
in that case you have very simple solution:L
$(document).ready(function(){
var OriginalSentence="howw are you?"
var ModifiedSentence="";
var splitstring=OriginalSentence.split(' ')
$.each(splitstring,function(i,v){
if(v!="")
{
//pass this word to your api and appedn it to sentance
ModifiedSentence+=APIRETURNVALUE//api return corrected value;
}
else{
ModifiedSentence+=v;
}
});
alert(ModifiedSentence);
});
Please review this one:
For string manipulation like this, I would highly recommend you to use Regex
Use online regex editor for faster try and error like here https://regex101.com/.
here I use /\w+/g to match every words if you want to ignore 1 or two words we can use /\w{2,}/g or something like that.
var str = "Hello howw are youu?";
var re = /\w+/g
var words = str.match(re);
console.log("Returning valus")
words.forEach(function(word, index) {
console.log(index + " -> " + word);
})
Correction
Just realize that you need to keep spacing as it is, please try this one:
I used your approach to change all to space. create array for its modified version then send to your API (I dunno that part). Then get returned data from API, reconvert it back to its original formating string.
var ori = `asdkhaskd asdkjaskdjaksjd askdjaksdjalsd a ksjdhaksjdhasd asdjkhaskdas`;
function replaceMeArr(str, match, replace) {
var s = str,
reg = match || /\s/g,
rep = replace || ` space `;
return s.replace(reg, rep).split(/\s/g);
}
function replaceMeStr(arr, match, replace) {
var a = arr.join(" "),
reg = match || /\sspace\s/g,
rep = replace || " ";
return a.replace(reg, rep);
}
console.log(`ori1: ${ori}`);
//can use it like this
var modified = replaceMeArr(ori);
console.log(`modi: ${modified.join(' ')}`);
//put it back
var original = replaceMeStr(modified);
console.log(`ori2: ${original}`);
Updated
var str = "Hello howw are youu?";
var words = str.split(" ");
// Getting an array without spaces/empty values
// send it to your API call
var requestArray = words.filter(function(word){
if (word) {
return word;
}
});
console.log("\nAPI Response that tell me which words to correct:");
console.log("6: how\n8: you");
var response = {
"1": "how",
"3": "you"
}
//As you have corrected words index, Replace those words in your "requestArray"
for (var key in response) {
requestArray[key] = response[key];
}
//now we have array of non-empty & correct spelled words. we need to put back empty (space's) value back in between this array
var count = 0;
words.forEach(function(word, index){
if (word) {
words[index] = requestArray[count];
count++;
}
})
console.log(words);
Correct me, if i was wrong.
Hope this helps :)
Try this JSFiddle
, Happy coding :)
//
// ReplaceMisspelledWords
//
// Created by Hilal Baig on 21/11/16.
// Copyright © 2016 Baigapps. All rights reserved.
//
var preservedArray = new Array();
var splitArray = new Array();
/*Word Object to preserve my misspeled words indexes*/
function preservedObject(pIndex, nIndex, title) {
this.originalIndex = pIndex;
this.apiIndex = nIndex;
this.title = title;
}
/*Preserving misspeled words indexes in preservedArray*/
function savePreserveIndexes(str) {
splitArray = str.split(" ");
//console.log(splitArray);
var x = 0;
for (var i = 0; i < splitArray.length; i++) {
if (splitArray[i].length > 0) {
var word = new preservedObject(i, x, splitArray[i]);
preservedArray.push(word);
x++;
}
}
};
function replaceMisspelled(resp) {
for (var key in resp) {
for (var i = 0; i < preservedArray.length; i++) {
wObj = preservedArray[i];
if (wObj.apiIndex == key) {
wObj.title = resp[key];
splitArray[wObj.originalIndex] = resp[key];
}
}
}
//console.log(preservedArray);
return correctedSentence = splitArray.join(" ");
}
/*Your input string to be corrected*/
str = "Hello howw are youu";
console.log(str);
savePreserveIndexes(str);
/*API Response in json of corrected words*/
var apiResponse = '{"1":"how","3":"you" }';
resp = JSON.parse(apiResponse);
//console.log(resp);
/*Replace misspelled words by corrected*/
console.log(replaceMisspelled(resp)); //Your solution
How would you search through an entire string and display each item found in a div?
The thing I'm searching for is a license code which starts with NVOS and ends with ". I'd like to extract the entire code except for the "
The thing I want to parse would be like NVOS-ABCD-EFG-HIJK-LM52P" but I don't want the " included.
Here is what I'm trying:
var myRe = /^NVOS[^"]*/g;
var myArray = myRe.exec(document.getElementById("txt").value);
console.log(myArray)
for (i in myArray){
console.log(i)
}
Not working.
Use a regular expression.
var myString = document.body.innerHTML // substitute for your string
var regex = /NVOS[A-Z\-]+/g // /g (global) modifier searches for all matches
var matches = myString.match(regex);
for (var i=0; i<matches.length; i++)
console.log( matches[i] )
// NVOS-ABCD-EFG-HIJK-LM
// NVOS-ABCD-EFG-HIJK-LM
lests say that your string is str.
//check if the code even have this characters /x22 is for = " //
var newString = str.substr(str.indexOf("NVOS"),str.lastIndexOf("\x22") -1);
If you want to display each section in the console, then you could do it like this:
var licenseString = "NVOS-ABCD-EFG-HIJK-LM52P";
var stringSplit = licenseString.split("-");
for(var part in stringSplit) {
console.log(stringSplit[part]);
}
I have the following regex where I am trying to capture the Ids of each start comment. But for some reason I am only able to capture the first one. It won't grab the Id of the nested comment. It only prints 1000 to the console. I am trying to get it to capture both 1000 and 2000. Can anyone spot the error in my regex?
<script type="text/javascript">
function ExtractText() {
var regex = /\<!--Start([0-9]{4})-->([\s\S]*?)<!--End[0-9]{4}-->/gm;
var match;
while (match = regex.exec($("#myHtml").html())) {
console.log(match[1]);
}
}
</script>
<div id="myHtml">
<!--Start1000-->Text on<!--Start2000-->the left<!--End1000-->Text on the right<!--End2000-->
</div>
Based on Mike Samuel's answer I updated my JS to the following:
function GetAllIds() {
var regex = /<!--Start([0-9]{4})-->([\s\S]*?)<!--End\1-->/g;
var text = $("#myHtml").html();
var match;
while (regex.test(text)) {
text = text.replace(
regex,
function (_, id, content) {
console.log(id);
return content;
});
}
}
In
<!--Start1000-->Text on<!--Start2000-->the left<!--End1000-->Text on the right<!--End2000-->
the "1000" region overlaps the "2000" region, but the exec loop only finds non-overlapping matches since each call to exec with the same regex and string starts at the end of the last match. To solve this problem, try
var regex = /<!--Start([0-9]{4})-->([\s\S]*?)<!--End\1-->/g;
for (var s = $("#myHtml").html(), sWithoutComment;
// Keep going until we fail to replace a comment bracketed chunk
// with the chunk minus comments.
true;
s = sWithoutComment) {
// Replace one group of non-overlapping comment pairs.
sWithoutComment = s.replace(
regex,
function (_, id, content) {
console.log(id);
// Replace the whole thing with the body.
return content;
});
if (s === sWithoutComment) { break; }
}
You can use grouping and then another regexp:
var regex = /(<!--Start)([0-9]{4})/ig;
var str = document.getElementById('myHtml').innerHTML;
var matches = str.match(regex);
for(var i=0;i<matches.length;i++){
var m = matches[i];
var num = m.match(/(\d+)/)[1];
console.log(num);
}
I'm writing a code for live replacement of specific words in a text field as the user types.
I'm using regex and javascript:
The first array has the regular expressions to be found, and the second array has the words that should replace any them.
source = new Array(/\srsrs\s/,/\sñ\s/,/\snaum\s/,/\svc\s/,/\scd\s/,/\sOq\s/,/\soke\s/,/\so\sq\s/,
/\soque\s/,/\soqe\s/,/\spq\s/,/\sq\s/,/\sp\/\s/g,/\spra\s/,/\sp\s/,/\stbm\s/,
/\stb\s/,/\std\s/,/\sblz\s/,/\saki\s/,/\svlw\s/,/\smara\s/,/\sqlq\s/,/\sqq\s/,
/\srpz\s/,/\smsm\s/,/\smto\s/,/\smtu\s/,/\sqro\s/,/\sqdo\s/,/\sqd\s/,/\sqnd\s/,
/\sqto\s/,/\sqm\s/,/\sjah\s/, /\sc\/\s/,/\scmg\s/,/\s\+\sou\s\-\s/,/\sflw\s/,
/\sxau\s/,/\sto\s/,/\sta\s/);
after = new Array("risos","não","não","você","cadê","o que","o que","o que","o que","o que","porque",
"que","para","para","para","também","também","tudo","beleza","aqui","valeu","maravilhoso",
"qualquer","qualquer","rapaz","mesmo","muito","muito","quero","quando","quando","quando",
"quanto","quem","Já","com","comego","mais ou menos","falow","tchau","estou","está");
This is the function that does the replacement:
function replacement(){
for(i=0; i<source.length; i++){
newtext = " "+document.getElementById("translation").value+" ";
console.log(newtext);
if(myregex = newtext.match(source[i])){
newafter = after[i];
rafael = myregex+" ";
document.getElementById("translation").value = document.getElementById("translation").value.replace(rafael, newafter);
}
}
}
My problem is every time the function is called to replace an expression with only one letter, the replacement is being made on the first occurrence of that letter, even within a word. I thought looking for that letter with \s before and after would solve it, but it didn't.
If you're looking only to match a word, you should put \b before and after (word boundary). This will ensure that you don't match parts of words. Also note that you are corrupting your regex by concatenating a string. Try this instead:
var in = document.getElementById("translation").value;
if( in.charAt(in.length-1) == " ") { // user has just finished typing a word
// this avoids interrupting the word being typed
var l = source.length, i;
for( i=0; i<l; i++) in = in.replace(source[i],after[i]);
document.getElementById("translation").value = in;
}
You need to add a g (global) modified to regexes so that it will replace all occurrences and use \b instead of \s to mark word boundaries.
source = new Array(/\brsrs\b/g,/\bñ\b/g, etc
On a side note, since all your regexes follow the same pattern it might be easier to just do:
source = new Array( 'rsr', 'ñ', 'naum', etc );
if( myregex = newtext.match( new Regexp( "\b"+source[i]+"\b", 'g' ) ) ) {
...
If by "live replacement" you mean calling function replacement at each keystroke then \b at the end will not help you, you should indeed use \s. However in your replacement function your are adding a space to the text field value so your single character words are triggering the replacement.
Here is my refactoring of your code :
(function () { // wrap in immediate function to hide local variables
source = [ [/\brsrs\s$/, "risos"], // place reg exp and replacement next to each other
[/\b(ñ|naum)\s$/, "não"], // note combined regexps
[/\bvc\s$/, "você"]
// ...
]; // not also use of array literals in place of new Array
document.getElementById ("translation").addEventListener ('keyup', function (ev) {
var t = this.value // fetch text area value
, m
, i = source.length;
while (i--) // for each possible match
if ((m = t.match(source[i][0]))) { // does this one match ?
// replace match : first remove the match string (m[0]) from the end of
// the text string, then add the replacement word followed by a space
this.value = t.slice (0, -m[0].length) + source[i][1] + ' ';
return; // done
}
}, false);
}) ();
And the fiddle is : http://jsfiddle.net/jFYuV
In a somewhat different style, you could create a function that encapsulated the list of substitutions:
var substitutions = {
"rsrs": "risos",
"ñ": "não",
"naum": "não",
"vc": "você",
// ...
};
var createSubstitutionFunction = function(subs) {
var keys = [];
for (var key in subs) {
if (subs.hasOwnProperty(key)) {
keys[keys.length] = key;
}
}
var regex = new RegExp("\\b" + keys.join("\\b|\\b") + "\\b", "g");
return function(text) {
return text.replace(regex, function(match) {
return subs[match];
});
};
};
var replacer = createSubstitutionFunction(substitutions);
You would use it like this:
replacer("Some text with rsrs and naum and more rsrs and vc")
// ==> "Some text with risos and não and more risos and você"