Back to Freecodecamp

Build a RegEx Sandbox

curriculum/challenges/english/blocks/lab-regex-sandbox/66e028680eca7d21db7e1aee.md

latest19.1 KB
Original Source

--description--

For this lab, you start with the CSS and HTML already written for you. You will use JavaScript to enable the regex sandbox to test a regular expression against a string and highlight the results.

Objective: Fulfill the user stories below and get all the tests to pass to complete the lab.

User Stories:

  1. You should access the #pattern, #test-string, #test-btn, and #result elements and save them in the variables regexPattern, stringToTest, testButton, and testResult, respectively.
  2. You should access the #i and #g flag checkboxes and save them in the variables caseInsensitiveFlag and globalFlag, respectively.
  3. You should have a function named getFlags that returns a string containing the flags from checked flag checkboxes, or an empty string if none of them have been checked.
  4. When you click the testButton button, if the regex pattern matches the test string, the matched text should be highlighted. To highlight the matches, replace each match with the same text surrounded by a span element with the class of highlight. Note that the CSS for that has been already added for you.
  5. When there's a match, the matched text should be displayed inside #result. In case of multiple matches, each matched text should be separated from the next one by a comma and a space.
  6. When there's no match, the text no match should be displayed inside #result.

--hints--

You should access the #pattern element and save it in the regexPattern variable.

js
assert.equal(regexPattern, document.querySelector('#pattern'))

You should access the #test-string element and save it in the stringToTest variable.

js
assert.equal(stringToTest, document.querySelector('#test-string'))

You should access the #test-btn element and save it in the testButton variable.

js
assert.equal(testButton, document.querySelector('#test-btn'))

You should access the #result element and save it in the testResult variable.

js
assert.equal(testResult, document.querySelector('#result'))

You should access the #i flag checkbox and save it in the caseInsensitiveFlag.

js
assert.equal(caseInsensitiveFlag, document.querySelector('#i'))

You should access the #g flag checkbox and save it in the globalFlag variable.

js
assert.equal(globalFlag, document.querySelector('#g'))

You should have a getFlags function.

js
assert.isFunction(getFlags)

The getFlags function should return "i" if the #i checkbox is checked.

js
caseInsensitiveFlag.checked = true;
globalFlag.checked = false;
assert.equal(getFlags(), "i")

The getFlags function should return "g" if the #g checkbox is checked.

js
caseInsensitiveFlag.checked = false;
globalFlag.checked = true;
assert.equal(getFlags(), "g")

The getFlags function should return either "ig" or "gi" if both checkboxes are checked.

js
caseInsensitiveFlag.checked = true;
globalFlag.checked = true;
const flags = getFlags();
assert.lengthOf(flags, 2);
assert.include(flags, "i");
assert.include(flags, "g");

The getFlags function should return an empty string if both checkboxes are not checked.

js
caseInsensitiveFlag.checked = false;
globalFlag.checked = false;
assert.equal(getFlags(), "")

When the inner HTML of stringToTest is Gu1n34 P1g5, the value of regexPattern is \d+, and no flag is checked, stringToTest.innerHTML should become Gu<span class="highlight">1</span>n34 P1g5 by clicking the testButton button.

js
stringToTest.innerText = "Gu1n34 P1g5"
regexPattern.value = "\\d+";
caseInsensitiveFlag.checked = false;
globalFlag.checked = false;
const testBtn = document.getElementById("test-btn");
testBtn.dispatchEvent(new Event("click"));
let expected = 'Gu<span class="highlight">1</span>n34 P1g5';
assert.equal(stringToTest.innerHTML, expected);

When the inner HTML of stringToTest is Gu1n34 P1g5, the value of regexPattern is \d+, and the global flag is checked, stringToTest.innerHTML should become Gu<span class="highlight">1</span>n<span class="highlight">34</span> P<span class="highlight">1</span>g<span class="highlight">5</span> by clicking the testButton button.

js
stringToTest.innerText = "Gu1n34 P1g5"
regexPattern.value = "\\d+";
caseInsensitiveFlag.checked = false;
globalFlag.checked = true;
const testBtn = document.getElementById("test-btn");
testBtn.dispatchEvent(new Event("click"));
let expected = 'Gu<span class="highlight">1</span>n<span class="highlight">34</span> P<span class="highlight">1</span>g<span class="highlight">5</span>';
assert.equal(stringToTest.innerHTML, expected);

When the inner HTML of stringToTest is Gu1n34 P1g5, the value of regexPattern is G, and both the global and case insensitive flags are checked, stringToTest.innerHTML should become <span class="highlight">G</span>u1n34 P1<span class="highlight">g</span>5 by clicking the testButton button.

js
stringToTest.innerText = "Gu1n34 P1g5"
regexPattern.value = "G";
caseInsensitiveFlag.checked = true;
globalFlag.checked = true;
const testBtn = document.getElementById("test-btn");
testBtn.dispatchEvent(new Event("click"));
let expected = '<span class="highlight">G</span>u1n34 P1<span class="highlight">g</span>5';
assert.equal(stringToTest.innerHTML, expected);

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.

js
stringToTest.innerText = "She sells seashells by the seashore."
regexPattern.value = "s[he]a?";
caseInsensitiveFlag.checked = true;
globalFlag.checked = true;
const testBtn = document.getElementById("test-btn");
testBtn.dispatchEvent(new Event("click"));
let expected = '<span class="highlight">Sh</span>e <span class="highlight">se</span>lls <span class="highlight">sea</span><span class="highlight">sh</span>ells by the <span class="highlight">sea</span><span class="highlight">sh</span>ore.';
assert.strictEqual(stringToTest.innerHTML, expected);

stringToTest.innerText = "She sells seashells by the seashore."
caseInsensitiveFlag.checked = false;
globalFlag.checked = true;
testBtn.dispatchEvent(new Event("click"));
expected = 'She <span class="highlight">se</span>lls <span class="highlight">sea</span><span class="highlight">sh</span>ells by the <span class="highlight">sea</span><span class="highlight">sh</span>ore.';
assert.strictEqual(stringToTest.innerHTML, expected);

stringToTest.innerText = "She sells seashells by the seashore."
globalFlag.checked = false;
testBtn.dispatchEvent(new Event("click"));
expected = 'She <span class="highlight">se</span>lls seashells by the seashore.';
assert.strictEqual(stringToTest.innerHTML, expected);

stringToTest.innerText = "She sells seashells by the seashore."
caseInsensitiveFlag.checked = true;
testBtn.dispatchEvent(new Event("click"));
expected = '<span class="highlight">Sh</span>e sells seashells by the seashore.';
assert.strictEqual(stringToTest.innerHTML, expected);

When there's no match, the test string shouldn't be modified.

js
stringToTest.innerText = "She sells seashells by the seashore."
regexPattern.value = "sea\\s";
const testBtn = document.getElementById("test-btn");
testBtn.dispatchEvent(new Event("click"));
let expected = 'She sells seashells by the seashore.';
assert.strictEqual(stringToTest.innerHTML, expected);

When the inner HTML of stringToTest is Gu1n34 P1g5, the value of regexPattern is \d+, and no flag is checked, the inner text of #result should become 1 by clicking the testButton button.

js
const out = document.getElementById("result");
stringToTest.innerText = "Gu1n34 P1g5"
regexPattern.value = "\\d+";
caseInsensitiveFlag.checked = false;
globalFlag.checked = false;
const testBtn = document.getElementById("test-btn");
testBtn.dispatchEvent(new Event("click"));
let expected = "1"
assert.strictEqual(out.innerText, expected)

When the inner HTML of stringToTest is Gu1n34 P1g5, the value of regexPattern is \d+, and the global flag is checked, the inner text of #result should become 1, 34, 1, 5 by clicking the testButton button.

js
const out = document.getElementById("result");
stringToTest.innerText = "Gu1n34 P1g5"
regexPattern.value = "\\d+";
caseInsensitiveFlag.checked = false;
globalFlag.checked = true;
const testBtn = document.getElementById("test-btn");
testBtn.dispatchEvent(new Event("click"));
let expected = "1, 34, 1, 5"
assert.strictEqual(out.innerText, expected)

When there's a match, the matched text should be displayed inside #result.

js
const out = document.getElementById("result");
stringToTest.innerText = "She sells seashells by the seashore."
regexPattern.value = "s[he]a?";
caseInsensitiveFlag.checked = true;
globalFlag.checked = true;
const testBtn = document.getElementById("test-btn");
testBtn.dispatchEvent(new Event("click"));
let expected = "Sh, se, sea, sh, sea, sh"
assert.strictEqual(out.innerText, expected)

stringToTest.innerText = "She sells seashells by the seashore."
caseInsensitiveFlag.checked = false;
testBtn.dispatchEvent(new Event("click"));
expected = "se, sea, sh, sea, sh"
assert.strictEqual(out.innerText, expected)

stringToTest.innerText = "She sells seashells by the seashore."
globalFlag.checked = false;
testBtn.dispatchEvent(new Event("click"));
expected = "se"
assert.strictEqual(out.innerText, expected)

stringToTest.innerText = "She sells seashells by the seashore."
caseInsensitiveFlag.checked = true;
testBtn.dispatchEvent(new Event("click"));
expected = "Sh"
assert.strictEqual(out.innerText, expected)

When there's no match, the text no match should be displayed inside #result.

js
const out = document.getElementById("result");
stringToTest.innerText = "She sells seashells by the seashore."
regexPattern.value = "sea\\s";
const testBtn = document.getElementById("test-btn");
testBtn.dispatchEvent(new Event("click"));
let expected = "no match";
assert.strictEqual(out.innerText, expected);

--seed--

--seed-contents--

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>
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;
}
js

--solutions--

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>
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;
}

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;
}
js
const regexPattern = document.getElementById("pattern");
const caseInsensitiveFlag = document.getElementById("i");
const globalFlag = document.getElementById("g");
const testResult = document.getElementById("result");
const getFlags = () => {
    let flags = '';
    const flagArray = [caseInsensitiveFlag, globalFlag]
    flagArray.forEach((flag) => {
        if (flag.checked) flags += flag.id;
    })
    return flags
}
const stringToTest = document.getElementById("test-string");
const testButton = document.getElementById("test-btn")
testButton.addEventListener(
    "click",
    () => {
        let matched;
        let flags = getFlags();
        const regex = new RegExp(regexPattern.value, flags)
        if (flags.includes(globalFlag)) {
            stringToTest.innerHTML = stringToTest.innerText.replaceAll(regex, '<span class="highlight">$&</span>')
            matched = stringToTest.innerText.matchAll(regex)
        } else {
            stringToTest.innerHTML = stringToTest.innerText.replace(regex, '<span class="highlight">$&</span>')
            matched = stringToTest.innerText.match(regex);             
        }
        testResult.innerText = matched ? matched.join(", ") : 'no match';
    }
)