Ok, so I’ve tried this a few ways and I’m a bit stuck. Replacing a regex matched text in a string is a breeze when it’s just one match. But when it’s several matches, it gets tricky. I’m not sure why I’m not passing these tests:
15. When you click the testButton
button, if the regex pattern matches the test string, the matched text should be surrounded by a span
element with the class of highlight
.
I am surrounding the text with a span.
19. When there’s a match, the matched text should be displayed inside #result
.
I am getting the result displayed, so this is odd.
I have made no changes to the HTML and CSS files already provided for by the exercise itself. Still, here is the HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<title>Regex Sandbox</title>
</head>
<body>
<h1>Regex Sandbox</h1>
<main>
<div id="regex-container">
<label for="pattern">Regex Pattern:
<div id="pattern-container">/<input type="text" id="pattern" name="pattern"
placeholder="Enter your regex pattern">/</div>
</label>
<div id="flags-container">
<p>Flags: </p>
<label for="i">
<input type="checkbox" name="flags" id="i"> i
</label>
<label for="g">
<input type="checkbox" name="flags" id="g"> g
</label>
</div>
</div>
<div id="test-container">
<p>Test String:</p>
<div id="test-string" placeholder="Enter your test string" contenteditable="true"></div>
</div>
<button class="btn" id="test-btn" type="button">Test Regex</button>
<div id="result-container">
<h2>Result:</h2>
<p id="result">
</p>
</div>
</main>
<script src="script.js"></script>
</body>
</html>
Here is the CSS:
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
:root {
--dark-grey: #1b1b32;
--light-grey: #f5f6f7;
--golden-yellow: #fecc4c;
--yellow: #ffcc4c;
--gold: #feac32;
--orange: #ffac33;
--dark-orange: #f89808;
--border: 0.2rem solid darkgrey;
--padding: 0.3rem;
}
body {
background-color: var(--dark-grey);
color: var(--light-grey);
font-size: 20px;
font-family: "Lato", Helvetica, Arial, sans-serif;
padding: 5px;
}
h1 {
margin: 5rem auto 2rem;
text-align: center;
}
p {
padding: var(--padding);
}
#regex-container {
max-width: 680px;
margin: 20px auto;
display: flex;
justify-content: center;
align-items: center;
border: var(--border);
}
#regex-container>label {
padding: var(--padding);
flex: 1 1 auto;
}
#pattern-container {
display: inline-block;
color: var(--dark-grey);
background-color: var(--light-grey);
margin: 5px;
border: var(--border);
}
#pattern {
margin: 0.2rem;
border: 0;
font-size: 1rem;
width: calc(100% - 1.2rem);
}
#pattern:focus {
outline: none;
}
#flags-container {
display: flex;
align-items: center;
flex: 1 1 auto;
}
#flags-container>label {
padding: var(--padding);
margin-right: 0.3rem;
}
#test-container {
max-width: 680px;
margin: 20px auto;
display: flex;
flex-direction: column;
flex: 0 0 auto;
border: var(--border);
}
#test-string {
background-color: var(--light-grey);
min-height: 5rem;
color: var(--dark-grey);
border-top: var(--border);
font-size: 1.2rem;
}
[contenteditable=true]:empty:before {
content: attr(placeholder);
pointer-events: none;
color: var(--dark-grey);
}
::placeholder {
color: var(--dark-grey);
}
button {
display: block;
cursor: pointer;
width: 8rem;
margin: 0.2rem auto;
color: var(--dark-grey);
background-color: var(--gold);
background-image: linear-gradient(var(--golden-yellow), var(--orange));
border-color: var(--gold);
border-width: 0.2rem;
font-size: 1.1rem;
}
.btn:hover {
background-image: linear-gradient(var(--yellow), var(--dark-orange));
}
#result-container {
max-width: 680px;
margin: 20px auto;
display: flex;
justify-content: center;
align-items: center;
}
h2 {
align-self: flex-start;
margin: 0.4rem 0.2rem 0.2rem;
flex: 0 1 auto;
}
#result {
color: var(--dark-grey);
background-color: var(--light-grey);
font-size: 1.5rem;
flex: 1 1 auto;
margin: 0.2rem;
border: var(--border);
min-height: 3rem;
}
.highlight {
background-color: lightgreen;
}
And this is my Javascript:
const regexPattern = document.getElementById("pattern");
const stringToTest = document.getElementById("test-string");
const testButton = document.getElementById("test-btn");
const testResult = document.getElementById("result");
const caseInsensitiveFlag = document.getElementById("i");
const globalFlag = document.getElementById("g");
// flags based on checked checkboxes
const getFlags = () => {
if(caseInsensitiveFlag.checked && globalFlag.checked) {
return "ig";
} else if(caseInsensitiveFlag.checked) {
return "i";
} else if(globalFlag.checked) {
return "g";
} else {
return "";
}
}
// supplementary function to get only "i" flag
const getiflag = () => {
if(caseInsensitiveFlag.checked) {
return "i";
}
return "";
}
// regex builder
const regexBuilder = (input) => {
let flags = getFlags();
let creation = new RegExp(input, flags);
return creation;
}
// surround text with tags to highlight
const highlighter = (text) => {
return `<span class="highlight">${text}</span>`;
}
// event listener
testButton.addEventListener('click', () => {
let regexInput = regexPattern.value; // input from regex
console.log(regexInput)
let lookarounds = "";
if(regexInput.includes("\d+")) {
lookarounds += `(?<!${regexInput})|(?!${regexInput})`;
} else {
lookarounds += `(?<=${regexInput})|(?=${regexInput})`;
}
let regex = regexBuilder(regexInput); // regex to check
let iFlag = getiflag();
let regexNoGlobal = new RegExp(regexInput, iFlag);
let regex2 = regexBuilder(lookarounds); // regex to split testInput when global flags is on
console.log(regex2);
let testInput = stringToTest.innerText; // gets input from test string
if(globalFlag.checked) { // rules to match when global flag is ON
if(regex.test(testInput)) {
// splits test string input to substrings with regex matched and unmatched items
let testInputArr = [...testInput.split(regex2)];
console.log(testInputArr);
let convertedArr = []; // creates new array to build with converted substrings
testInputArr.forEach((item) => {
if(regexNoGlobal.test(item)) { // if substring includes regex
let matchedText = item.match(regexNoGlobal); // gets matched text
let highlightedText = highlighter(matchedText); // adds span tags to matched text
let newItem = item.replace(matchedText, highlightedText); // replaces matched text with highlighted text
convertedArr.push(newItem); // adds converted item to array
} else {
convertedArr.push(item); // adds original item to array
}
});
let textToDisplay = convertedArr.join(""); // joins items as uninterrupted string
stringToTest.innerHTML = textToDisplay; // sets html string to display
let resultsArr = [];
let resultsList = document.querySelectorAll(".highlight");
for(let i = 0; i < resultsList.length; i++) {
let keyItem = resultsList[i].innerText;
resultsArr.push(keyItem);
}
testResult.innerText = resultsArr.join(", "); // shows matched items in Result
} else {
testResult.innerText = "no match";
}
} else if(!globalFlag.checked) { // rules to match when global flag is OFF
if(regex.test(testInput)) {
let matchText = testInput.match(regex)[0];
let highlightedText = highlighter(matchText);
let textToDisplay = testInput.replace(matchText, highlightedText);
stringToTest.innerHTML = textToDisplay;
testResult.innerText = matchText;
} else {
testResult.innerText = "no match";
}
}
})