I am basically trying to edit this extension (AlertForWords-1.0.0) so that if it finds a specific word, it will alert me and play a sound. But the problem is, it doesn't produce any sounds at all. Here is the code:
let text = document.body.innerText
let textToFind = ""
chrome.storage.sync.get({
text: '',
time: 1000
}, (items) => {
textToFind = items.text;
let regexStr = "("
textToFind.split("\n").forEach((word, index) => {
if (index != textToFind.split("\n").length-1) {
regexStr += word + "|"
} else {
regexStr += word
}
});
regexStr += ")"
let regex = new RegExp(regexStr, "gi")
const mp3_url = 'https://media.geeksforgeeks.org/wp-content/uploads/20190531135120/beep.mp3';
let src = 'https://file-examples.com/wp-content/uploads/2017/11/file_example_MP3_700KB.mp3';
let audio = new Audio(src);
setTimeout(() => {
let found = text.match(regex)
if (found) {
//new Audio(mp3_url).play();
audio.play();
alert(`Found Word --`)
}
}, items.time)
});
Any suggestions are appreciated. I've been trying a few different things but nothing seems to work.
How can I use regex to get an array of all the individual characters not contained within anchor tags?
So for example, with this text:
DOWNLOAD THIS OR THAT
I want an array of the indices for the characters D,O,W,N,L,O,A,D, ,T,H,I,S, , ... etc.
I managed to figure out how to get everything I don't want selected, using this: /(?:<.*?>)
But I don't know how to use that to get all the characters outside of that group.
As already pointed out by #Cid, don't do this with regular expressions. Instead, use something like below and read the input character by character:
function reader(el) {
let i = 0;
let src = el.innerHTML;
const r = {
done() {
return i >= src.length;
},
advance() {
i += 1;
},
char() {
let c = !r.done() ? src[i] : '';
r.advance();
return c;
},
peek() {
return !r.done() ? src[i] : '';
}
};
return r;
}
function collector(el) {
const r = reader(el);
const skipUntil = char => {
while (r.peek() !== char) {
r.advance();
}
r.advance();
};
return {
collect() {
const v = [];
while (!r.done()) {
if (r.peek() === '<') {
skipUntil('>');
} else if (r.peek() === '\n') {
r.advance();
} else {
v.push(r.char());
}
}
return v;
}
};
}
/* --- */
const el = document.querySelector('#source');
const cl = collector(el);
console.log(cl.collect());
<div id="source">
DOWNLOAD THIS OR THAT
</div>
My input is
const text = 'Hello #kevin12 How are you?'
How I render it
<span>{text}</span>
How I want to render it
<span>Hello <em>#kevin12</em> How are you?</span>
My parsing function (incomplete)
const parseText = value => {
const mention = value.substring(value.lastIndexOf('#')+1)
const words = value.split(mention)
return words.map(word => word === mention ? React.createElement('em', {}, word) : word)
}
...
<span>{parseText(text)}</span>
Please help me complete this rendering function.
const parseText = value => {
const words = value.split(' ')
return words.map((word, index) => {
if (index !== words.length - 1) {
word += " "
}
return word[0] === '#' ? <em>{word}</em> : word;
})
}
Split by words, iterate over the array and find the item that start with #
export default function App() {
const text = "Hello #kevin12 How are you?";
const parseText = value => {
const mention = value.split(" ");
return mention.map(w => (w[0] === "#" ? <em> {w} </em> : <> {w}</>));
};
return (
<span>
<span>{parseText(text)}</span>
</span>
);
}
I will suggest going through the regex, here is the sample code
const text = 'Hello #kevin12 How are you?';
let finalResult = test;
let re =/(?:^|\W)#(\w+)(?!\w)/g;
let match,matches =[];
while(match =re.exec(test)){
let found ='#'+match[1];
let replace ='<em>'+found+'</em>';
finalresult =finalResult.replace(found,replace);
}
console.log(finalResult) ;
I'm trying to highlight a certain body string. So if there is an # #username highlight part of the string, and leave the rest of the content unhighlighted. Very similar to how discord mentions a user.
So im trying to implement that logic
The issue is that it's highlighting the wrong parts of the string. For example
const regex = /^#/i;
const words = comment.comment_body.split(" ");
let highLight;
let username;
for (let i = 0; i < words.length; i++) {
const word = words[i];
console.log("checking for word", word);
if (regex.test(word)) {
username = word
console.log("test passed");
highLight = <ReactMarkdown className="highlightMention" source={word} />;
} else {
highLight = <ReactMarkdown className="markdownStyle" source={comment.comment_body} />;
}
}
.....
{comment.gifUrl === "" && highLight}
Map the splitted workds and if that words starts with # return it inside the highlighter else return the normal word :
const Component = () => {
...
return <div>{ comment.comment_body.split(' ').map(word=>{
if(word.startsWith('#')){
return <ReactMarkdown className="highlightMention" source={body} />;
}else{
return " "+word ;
}
})}
</div>;
};
const regex = /^#/i;
const words = comment.comment_body.split(" ");
let highLight = [];
let username;
for (let i = 0; i < words.length; i++) {
const word = words[i];
console.log("checking for word", word);
if (regex.test(word)) {
username = word
console.log("test passed");
// `highLight = <ReactMarkdown className="highlightMention" source={word} />;` this line will only do `highlight` for the last `word`
highLight.push(<ReactMarkdown className="highlightMention" source={word} />);
} else {
highLight.push(<ReactMarkdown className="markdownStyle" source={comment.comment_body} />);
}
}
.....
{comment.gifUrl === "" && highLight}
Is there any easy way to parse the following string to array. I can convert array to string but no idea how to convert back to array.
// Input
"Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6"
// Output
[
{
all: ["Keyword1", "Keyword2"],
any: ["Keyword3", "Keyword4"],
not: ["Keyword5", "Keyword6"]
}
]
// Input
"(Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6) OR (Keyword7 Keyword8 (Keyword9 OR Keyword10) -Keyword11 -Keyword12)"
// Output
[
{
all: ["Keyword1", "Keyword2"],
any: ["Keyword3", "Keyword4"],
not: ["Keyword5", "Keyword6"]
},
{
all: ["Keyword7", "Keyword8"],
any: ["Keyword9", "Keyword10"],
not: ["Keyword11", "Keyword12"]
}
]
First things first:
I don't validate the input. This answer gives you an approach. You should validate the input, especially since you say it comes from the user :)
We will make use of the matchRecursive function from this blog.
This function will help us group the correct parentheses.
var matchRecursive = function () {
var formatParts = /^([\S\s]+?)\.\.\.([\S\s]+)/,
metaChar = /[-[\]{}()*+?.\\^$|,]/g,
escape = function (str) {
return str.replace(metaChar, "\\$&");
};
return function (str, format) {
var p = formatParts.exec(format);
if (!p) throw new Error("format must include start and end tokens separated by '...'");
if (p[1] == p[2]) throw new Error("start and end format tokens cannot be identical");
var opener = p[1],
closer = p[2],
/* Use an optimized regex when opener and closer are one character each */
iterator = new RegExp(format.length == 5 ? "["+escape(opener+closer)+"]" : escape(opener)+"|"+escape(closer), "g"),
results = [],
openTokens, matchStartIndex, match;
do {
openTokens = 0;
while (match = iterator.exec(str)) {
if (match[0] == opener) {
if (!openTokens)
matchStartIndex = iterator.lastIndex;
openTokens++;
} else if (openTokens) {
openTokens--;
if (!openTokens)
results.push(str.slice(matchStartIndex, match.index));
}
}
} while (openTokens && (iterator.lastIndex = matchStartIndex));
return results;
};
}();
Next, this is the algorithm I would use based on the data you provided:
we determine if we have 1st kind of input or 2nd type, by simply checking if str.startsWith("(");
we initialize the followings:
groupedItems for an array that will transform 2nd type of input into 1st type of input, so that we use the same code for both afterwards
returnArr for the returned data
We loop over the groupedItems and prepare an empty keywordObj
In this loop, we determine which are the any keywords by making use of the matchRecursive function and splitting the result after ' OR ' - the resulting items will be any items
For the rest of the keywords (all or not) we need to get to a single word - so we split again, this time after " ", the result of the split being an array of keywords
We loop over the keywords and determine if they are not keywords by checking if they start with -, otherwise we treat them as all keywords.
Here's the code for it:
function output(str){
var groupedItems = [];
if(str.startsWith("(")){
groupedItems = matchRecursive(str,"(...)");
} else {
groupedItems.push(str);
}
var returnArr = [];
for (var i = 0; i<groupedItems.length;i++){
var keywordObj = {all:[], any:[], not: []};
var thisGroup = groupedItems[i];
var arr = matchRecursive(thisGroup, "(...)");
if (arr.length != 1) throw new Error("unexpected input");
keywordObj.any = arr[0].split(" OR ");
var restOfKeywords = thisGroup.split(" (" + arr[0] + ") ");
for (var j = 0; j<restOfKeywords.length; j++){
var keyWords = restOfKeywords[j].split(" ");
for (var k = 0; k<keyWords.length;k++){
if (keyWords[k].startsWith("-"))
keywordObj.not.push(keyWords[k])
else
keywordObj.all.push(keyWords[k])
}
}
returnArr.push(keywordObj);
}
return returnArr;
}
// input "(Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6) OR (Keyword7 Keyword8 (Keyword9 OR Keyword10) -Keyword11 -Keyword12)"
// output [{"all":["Keyword1","Keyword2"],"any":["Keyword3","Keyword4"],"not":["-Keyword5","-Keyword6"]},{"all":["Keyword7","Keyword8"],"any":["Keyword9","Keyword10"],"not":["-Keyword11","-Keyword12"]}]
Here is a solution https://codepen.io/anon/pen/NXMoqo?editors=0012
{
// test cases
// const input = 'Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6';
const input = '(Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6) OR (Keyword7 Keyword8 (Keyword9 OR Keyword10) -Keyword11 -Keyword12)';
// const input = '((Keyword1 OR Keyword2 OR Keyword3) Keyword4 Keyword6 -Keyword5 -Keyword7) OR (Keyword8 Keyword9 (Keyword10 OR Keyword11) -Keyword12 Keyword13 -Keyword14 -Keyword15)';
const output = [];
input.split(') OR (').forEach(group => {
let trimmedGroup = group.replace(/^\(/, '').replace(/\)$/, '');
let anyGroup = trimmedGroup.match(/\(.+\)/).join('').replace(/[OR\)\(]/g, '').match(/\w+/g);
let notGroup = trimmedGroup.match(/-\w+/g).map(element => element.replace('-', ''));
let allGroup = trimmedGroup.replace(/\(.+\)/g, '').replace(/-\w+/g, '').match(/\w+/g);
output.push({
all: allGroup,
any: anyGroup,
not: notGroup
});
});
console.log(output);
}
can you check this
var arr = [], obj = {any:[], not:[], all: []};
function splitString(str) {
var object = JSON.parse(JSON.stringify(obj));
var strArr = str.split(" ");
var i=0;
while(strArr.length !== 0 && i<10) {
newStr = strArr.splice(0, 1)[0];
if(newStr.indexOf("(") != -1) {
while(newStr.indexOf(")") == -1) {
object.any.push(newStr.replace(")", "").replace("(", ""))
strArr.splice(0, 1);
newStr = strArr.splice(0, 1)[0];
}
object.any.push(newStr.replace(")", ""))
} else if(newStr.indexOf("-") != -1) {
object.not.push(newStr.substring(1).replace(")", ""))
} else {
object.all.push(newStr.replace(")", ""))
}
i++;
}
arr.push(object)
}
function convertToObj(string){
if(string.indexOf(") OR ") !== -1){
string.split(") OR ").forEach(function(str){
splitString(str.substring(1));
});
} else {
splitString(string);
}
}
convertToObj("Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6")
convertToObj("(Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6) OR (Keyword7 Keyword8 (Keyword9 OR Keyword10) -Keyword11 -Keyword12)")
console.log(arr)