I'm trying to write a regex that match a fixed alphanumeric string that may contain dots.
This regex will have to match all the characters but the dots.
I would need to use this in Javascript search() for comparing two strings.
Word to find: 30A10Z20
All of those are a correct match:
30A1.0Z2.0
30A.10Z20
3.0.A10.Z20
3.0.A.1.0.Z.2.0.
I've written these but with no success:
^30A10Z20\\.{0,1}?$
^30A10Z20\\.?$
^30A10Z20(?=\\.)
Any leads or help will be very much appreciated.
I'm not sure a RegExp will be the best way to do what I suppose you want to do (based on yur comments: try reformulating your question). Would this snippet be an idea?
const findTerm = (word, searchTerm) =>
word.replace(/[^a-z0-9]/gi, "") === searchTerm;
const aFewStrings = [
`something 30A1.0Z2.0 etc`,
`30A.10Z20 hithere`,
`Hello 3.0.A10.Z20`,
`The value 3.0.....A.1.0....Z.2.0. may be valid`,
`As may be the value 3.0###A.1.0#&!'Z.2.0.`,
`Bye 3.0.A.1.0.Z.2.0. ended`,
];
aFewStrings.forEach(s => {
const words = s.split(" ").map( w => findTerm(w, "30A10Z20") ? `<b>${w}</b>` : w );
console.log(words.join(" "));
});
If you want parts of the string (cf your comment), you have to do a bit of parsing. Something like:
const findTerm = (word, searchTerm) =>
RegExp(`(${searchTerm})`, "i").test(word.replace(/[^a-z0-9]/gi, ""));
const toBold = (word, searchTerm) => {
const word2Parse = [...word];
const wordPreserved = word2Parse.slice(0);
const len = searchTerm.length;
let foundIndices = [];
let i = 0;
while (word2Parse.length) {
const noDots = word2Parse.slice(1).filter(v => !/[^a-z0-9]/i.test(v));
const next = searchTerm.length > 1 && noDots[0] === searchTerm[1];
const found = searchTerm.length > 1
? word2Parse[0] === searchTerm[0] && next
: word2Parse[0] === searchTerm[0];
searchTerm = found ? searchTerm.slice(1) : searchTerm;
found && foundIndices.push(i);
i += 1;
word2Parse.shift();
}
wordPreserved[foundIndices[0]] = `<b>${wordPreserved[foundIndices[0]]}`;
wordPreserved[foundIndices.slice(-1)] = `${
wordPreserved[foundIndices.slice(-1)]}</b>`;
return wordPreserved.join("");
}
const aFewStrings = [
`something 30A1.0Z2.0 etc`,
`30A.10Z20 hithere`,
`Hello 3.0.A10.Z20`,
`The value 3.0.....A.1.0....Z.2.0. may be valid`,
`As may be the value 3.0###A.1.0#&!'Z.2.0.`,
`Bye 3.0.A.1.0.Z.2.0. ended`,
`3.0.A.1.0.Z.2.....0`,
];
const result = document.querySelector("#result");
let term = `30A1`;
result.appendChild(
Object.assign(
document.createElement("p"), {
innerHTML: `[1 String, search '30A1']: ${
(aFewStrings[3].split(" ")
.map(w =>
findTerm(w, term) ? toBold(w, term) : w)
.join(" "))}`
})
);
term = `notfound`;
result.appendChild(
Object.assign(
document.createElement("p"), {
innerHTML: `[1 String, search 'notfound']: ${
(aFewStrings[1].split(" ")
.map(w =>
findTerm(w, term) ? toBold(w, term) : w)
.join(" "))}`
})
);
term = `0Z20`;
aFewStrings.forEach(s => {
const words = s.split(" ").map(w =>
findTerm(w, term) ? toBold(w, term) : w);
result.appendChild(
Object.assign(
document.createElement("div"), {
innerHTML: words.join(" ")
})
);
});
body {
margin: 2rem;
font: normal 12px/15px verdana, arial;
}
b {
color: red;
}
<div id="result"></div>
Related
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>
I have the following code, I have some urls with markdown ("a" and "b") and others without ("c" and "d"), I have to make sure to turn them into an array of string url, as seen below.
How can I make some suggestions?
let a = "a [this](https://upload.wikimedia.org/wikipedia/commons/thumb/7/7e/T._rex_infection.png/440px-T._rex_infection.png)!"
let b = "b [this](https://upload.wikimedia.org/wikipedia/commons/thumb/7/7e/T._rex_infection.png/440px-T._rex_infection.png)! - [this](https://upload.wikimedia.org/wikipedia/commons/thumb/a/a9/Mosasaurus-Skelett.jpg/440px-Mosasaurus-Skelett.jpg)"
let c = "https://upload.wikimedia.org/wikipedia/commons/thumb/7/7e/T._rex_infection.png/440px-T._rex_infection.png"
let d = ["https://upload.wikimedia.org/wikipedia/commons/thumb/7/7e/T._rex_infection.png/440px-T._rex_infection.png", "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a9/Mosasaurus-Skelett.jpg/440px-Mosasaurus-Skelett.jpg"]
let e = "['https://upload.wikimedia.org/wikipedia/commons/thumb/c/c9/Tyrannosaurus_rex_Sue_at_FMNH.jpg/440px-Tyrannosaurus_rex_Sue_at_FMNH.jpg']"
let f = "['https://upload.wikimedia.org/wikipedia/commons/thumb/c/c9/Tyrannosaurus_rex_Sue_at_FMNH.jpg/440px-Tyrannosaurus_rex_Sue_at_FMNH.jpg','https://upload.wikimedia.org/wikipedia/commons/thumb/b/bc/Mosasaurus_beaugei_34.JPG/440px-Mosasaurus_beaugei_34.JPG']"
const url = (text, autoMatch = false) => {
if (!autoMatch) return [text].flat();
if (autoMatch) {
const match = text.match(/\((.*)\)/);
console.log("*", match, ";")
if (match === null) return "";
return match[1] || "";
}
};
console.log(url(a, true))
console.log(url(b, true))
//console.log(url(c))
//console.log(url(d))
I think it can helps you:
const getLinksFromString = (text) => text.match(/https[^ '")]*/gi);
const getLinks = (data) => {
switch (typeof data) {
case 'string':
return getLinksFromString(data);
case 'object':
const links = [];
for (text of data) {
links.push(...getLinksFromString(text));
}
return links;
}
}
const data = "b [this](https://upload.wikimedia.org/wikipedia/commons/thumb/7/7e/T._rex_infection.png/440px-T._rex_infection.png)! - [this](https://upload.wikimedia.org/wikipedia/commons/thumb/a/a9/Mosasaurus-Skelett.jpg/440px-Mosasaurus-Skelett.jpg)"
console.log(getLinks(data))
I am leaving this answer here because it took me about an hour+ to solve and I am hoping to help anyone else looking for a similar answer.
The question has a few parts that are all answered in separate SO posts:
Read a text file in javascript
Parse the text to get a space delimited string, excluding special characters, tabs, new lines, etc.
Count the number of each word
Display a list in descending order
Starting with an input that accepts a file and a function that will eventually sort our string, ezString:
return (
<div>
<input type="file" onChange={e => showFile(e)}/>
{ezString ? getSortedArr() : null}
</div>
);
and a function to turn that file into text (with a useState var ezString)
const [ezString, setEzString] = useState(null)
const showFile = async (e) => {
e.preventDefault()
const reader = new FileReader()
reader.onload = async (e) => {
const file = e.target.result
const goodString = file.replaceAll(/\s\s+/g, ' ')
.replaceAll(/(\r\n|\r|\n)/g, ' ')
.replaceAll(/[^a-zA-Z ]/g, "").toLowerCase()
setEzString(goodString);
};
reader.readAsText(e.target.files[0])
}
and a sorting function
const getSortedArr = () => {
let wordArray = ezString.split(' ').filter(n => n)
let wordCount = {};
for (let word of wordArray) {
if (wordCount[word]) {
wordCount[word] = wordCount[word] + 1
} else {
wordCount[word] = 1
}
}
let sortedArr = Object.entries(wordCount).sort((a, b) => b[1] - a[1])
return sortedArr ? sortedArr.map(arr => {
return (
<div key={arr[0]}>
<p style={{fontSize: 16}}>{arr[0]}: {arr[1]}</p>
</div>)
}) : null
}
With these parts we have the full component:
import React, {useState} from 'react'
const WordCounter = () => {
const [ezString, setEzString] = useState(null)
const showFile = async (e) => {
e.preventDefault()
const reader = new FileReader()
reader.onload = async (e) => {
const file = e.target.result
const goodString = file.replaceAll(/\s\s+/g, ' ')
.replaceAll(/(\r\n|\r|\n)/g, ' ')
.replaceAll(/[^a-zA-Z ]/g, "").toLowerCase()
setEzString(goodString);
};
reader.readAsText(e.target.files[0])
}
const getSortedArr = () => {
let wordArray = ezString.split(' ').filter(n => n)
let wordCount = {};
for (let word of wordArray) {
if (wordCount[word]) {
wordCount[word] = wordCount[word] + 1
} else {
wordCount[word] = 1
}
}
let sortedArr = Object.entries(wordCount).sort((a, b) => b[1] - a[1])
return sortedArr ? sortedArr.map(arr => {
return (
<div key={arr[0]}>
<p style={{fontSize: 16}}>{arr[0]}: {arr[1]}</p>
</div>)
}) : null
}
return (
<div className="App">
<input type="file" onChange={e => showFile(e)}/>
{ezString ? getSortedArr() : null}
</div>
);
}
export default WordCounter;
Areas for improvement:
I'm terrible with regex, thus the terrible regex and the need to filter empty strings out of the wordArray
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) ;
let str = 'Delete {%{"color":"#fff","content":"1"}%} item from my server';
const reworkString = (str) => {
let separators = ['{%', '%}'];
let newStr = str.split(new RegExp(separators.join('|'), 'g'));
const objChecker = (el) => {
JSON.parse(el)
console.log(el)
return elm.hasOwnProperty('content');
}
newStr = newStr.map(item=>{
if (objChecker(item)) {
return 'good'
}
else {
return item
}
})
}
reworkString(str);
function objChecker is not working I pass to JSON.parse(el) string but I get error Unexpected token D in JSON at position 0
try do json stringify first, but it always return string, not an object,
the main idea is I want to do is if its some element from arr, parse it to object
Your array also contains strings that are not JSON and cannot be parsed. If you want to skip over these, then make sure to put a try catch around the JSON.parse:
let str = 'Delete {%{"color":"#fff","content":"1"}%} item from my server';
const reworkString = (str) => {
let separators = ['{%', '%}'];
let newStr = str.split(new RegExp(separators.join('|'), 'g'));
const objChecker = (el) => {
try {
JSON.parse(el)
} catch (e) {
return false;
}
return el.hasOwnProperty('content');
}
newStr = newStr.map(item=>{
if (objChecker(item)) {
return 'good'
}
else {
return item
}
})
}
reworkString(str);