Search code examples
javascriptregexsafariregex-lookarounds

What is a good JS/Regex Positive Lookbehind Alternative in Safari for splitting text including hyphens?


I've read through a great article how to position and scale text in SVG-Circles. The text-wrapping algorithm shown there is using following line of code:

const words = text.split(/\s+/g); // To hyphenate: /\s+|(?<=-)/

The idea of this snippet is to create a list out of a word "Self-Sizing Text in a Circle" -> ["Self-Sizing", "Text", "in", "a", "Circle"].

^^The algorithm is working like a charm, but the hyphenate-version is not working in Safari:

const words = text.split(/\s+|(?<=-)/g); // Not working in Safari

Invalid regular expression: invalid group specifier name

The outcome should be ["Self-", "Sizing", "Text", "in", "a", "Circle"]. Notice the split of "Self-Sizing" keeping the hyphen as part of word one.

To get the example running in all browsers I bring up this solution:

text = text.replace(/-/g, "- "); // add a space next to the hyphen
const words = text.split(/\s+/g); // split using spaces

However solving this in a regex exclusive way seems to be most elegant especially when widening the scope of characters to be used for wrapping.

Therefore I'd like to ask you as a community whether you have a better idea.

A full playground can be found here (helpers.js -> line 7) or you can have a look into the Stack Snipped below:

const text = "Self-Sizing Text in a Circle";
const words = text.split(/\s+|(?<=-)/g);
console.log(words);


Solution

  • The .split(/\s+|(?<=-)/) operation means the string is split into chunks of non-whitespace chars and at the locations right after a - char. It means you can extract any chunks of chars other than whitespace with an optional hyphen right after, or any other hyphen (that will actually be the hyphen(s) right after the first alternative).

    const words = text.match(/[^\s-]+-?|-/g)
    

    See the regex demo. Details:

    • [^\s-]+-? - one or more chars other than whitespace and - and then an optional hyphen
    • | - or
    • - - a hyphen.

    See the JavaScript demo:

    const text = "Self-Sizing Text in a Circle";
    const words = text.match(/[^\s-]+-?|-/g)
    console.log(words);

    Note that if you do not need to care for consecutive, leading and trailing hyphens, you can simply use

    const words = text.match(/[^\s-]+-?/g)
    

    [^\s-]+-? will match one or more chars other than whitespace and - and then a single optional -.