Why aren't these regular expressions not working with exclamation point?

Viewed 36

Background info: I have some code that should pull results from a subreddit whenever they have the flair "loot", look for codes in the format XXXX-XXXX-XXXX, XXXX-XXXX-XXXX-XXXX, or those two without dashes, and output the codes in the console to be copy-pasted in another window. I also have it output any erroneous codes at the bottom for manual input later. The code runs fine, but the output is not the way that I want it, as explained later.

Currently, the code works perfectly with alphanumeric codes, but gives an error when an "!" is in the code. I have set the range to include !, so I do not know what is setting off the error. I also have the code over at https://www.mycompiler.io/view/EgXpTO0 , which can be run there to see what I see.

// not a module format, so you can run it in online compilers
"use strict";

async function main() {
    let https = require('https')

    let url_search_loot = 'https://www.reddit.com/r/idlechampions/search.json?q=flair_name%3A%22loot%22&restrict_sr=1&sort=new'
    let code_one_letter_range = '0-9a-zA-Z!'

    let code_one_letter_rx = '[' + code_one_letter_range + ']'
    let code_one_letter_not_rx = '[^' + code_one_letter_range + ']'

    let patterns = [
        // 4 groups of XXXX (4 X) joined by '-': i.e. XXXX-XXXX-XXXX-XXXX
        Array(4).fill(code_one_letter_rx + '{4}').join("\\-"),
        // 3 groups of --""--
        Array(3).fill(code_one_letter_rx + '{4}').join("\\-"),
        // 16 X - i.e. just as first pattern, but without '-' delmiters
        code_one_letter_rx + '{16}',
        // 12 X
        code_one_letter_rx + '{12}',
    ]
    patterns.forEach((val, idx, array) => array[idx] = '\\b(' + val + ')\\b')
    let all_patterns = RegExp(patterns.join('|'))

    // console.log(patterns, all_patterns)
    // exit(0)

    function https_get_promise(url, resolve, reject) {
        return https.get(url_search_loot, (res) => {
            let data = '';

            res.on('data', (chunk) => data += chunk)

            res.on('end', () => {
                res.data = data
                resolve(res)
            })

        }).on('error', (err) => reject(err))
    }


    let request = new Promise((resolve, reject) => https_get_promise(url_search_loot, resolve, reject))
    let res = await request
    let res_obj = JSON.parse(res.data)

     //console.log(res_obj.data.children)

    let errors = []
    res_obj.data.children.forEach((post, idx) => {
        // console.log(post.data.selftext)

        let match = post.data.selftext.match(all_patterns)
        if (!match) {
            errors.push(post)
        } else {
            console.log(match[0])
        }
    })

      if (errors.length > 0) {
        console.log("\n\n\n=== Errors ===")
        for (const post of errors) {
            console.log(post.data.selftext)
            console.log('======')
        }
    }
}

main()
1 Answers

The reason your codes do not work when they end with an "!" is because \b indicates a position of a word boundary ((^\w|\w$|\W\w|\w\W)). ! is not a part of a word.

To fix this, you can use something like: (^(?=[\w!])|(?<=[\w!])$|(?<=[^\w!])(?=[\w!])|(?<=[\w!])(?=[^\w!])) at the end.

This regex is essentially \b, with ! included.

// Assuming exclamation marks only appear at the end of the code.
const markEndRegex = "(^(?=[\\w!])|(?<=[\\w!])$|(?<=[^\\w!])(?=[\\w!])|(?<=[\\w!])(?=[^\\w!]))";
patterns.forEach((val, idx, array) => array[idx] = '\\b(' + val + ')' + markEndRegex);
Related