ARTICLE AD BOX
Background
I'm working on processing a comma-separated username list (for an ACL whitelist optimization in my project) and need to normalize whitespace around commas, as well as trim leading/trailing whitespace from the string.
Code & Issue
I used this regex replacement to clean up the string:
const input = "a,b,c "; const result = input.replace(/\s*,\s*|^\s*|\s*$/g, ','); console.log(result); // Outputs "a,b,c,," (two trailing commas) "a,b,c ".replace(/\s*,\s*|^\s*|\s*$/g, ',') // outputs two tailing commas "c ".replace(/(\s*$)/g, ','); // outputs two tailing commas function checkByIndexOf(commaStr, target) { const wrappedStr = `,${commaStr},`; const wrappedTarget = `,${target},`; return wrappedStr.indexOf(wrappedTarget) !== -1; } /** * High-performance check: indexOf + boundary validation (supports spaces/dots/no special chars) * @param {string} commaStr - Comma-separated string (may contain spaces, dots) * @param {string} target - Target item (may contain dots) * @returns {boolean} Whether the target is included as a standalone item */ function checkByIndexOfWithBoundary(commaStr, target) { const targetLen = target.length; const strLen = commaStr.length; let pos = commaStr.indexOf(target); // Return false immediately if target is not found if (pos === -1) return false; // Loop through all matching positions (avoid missing matches, e.g., duplicate items) while (pos !== -1) { // Check front boundary: start of string / previous char is comma/space const prevOk = pos === 0 || /[, ]/.test(commaStr[pos - 1]); // Check rear boundary: end of string / next char is comma/space const nextOk = (pos + targetLen) === strLen || /[, ]/.test(commaStr[pos + targetLen]); // Return true if both boundaries match (target is a standalone item) if (prevOk && nextOk) return true; // Find next matching position (avoid re-matching the same position) pos = commaStr.indexOf(target, pos + 1); } // All matching positions fail boundary validation return false; } /** * Check if a comma-separated string contains a specified standalone item * @param {string} commaStr - Original comma-separated string (e.g. "apple,banana,orange") * @param {string} target - Target string to check (e.g. "banana") * @returns {boolean} Whether the target item is included as a standalone entry */ function checkCommaStrInclude(commaStr, target) { // Escape regex special characters in the target string (e.g. . * + ? $ ^ [ ] ( ) { } | \ /) const escapedTarget = target.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // Build regex pattern: match (start of string | comma) + escaped target + (comma | end of string) // Ensures the target is a standalone item (avoids partial matches) const regex = new RegExp(`(^|,)${escapedTarget}(,|$)`, 'g'); // Test if the regex matches the comma-separated string return regex.test(commaStr); }Problem
The expected output is "a,b,c" (no trailing commas, normalized commas), but the current code produces two trailing commas instead. I don't understand why the regex is matching in a way that adds extra commas at the end.
