3

Just wondering if anyone has a tried & tested regex to parse a css font string into its various pieces:

  • 12px arial
  • italic bold sans-serif
  • 12px/50px verdana
  • etc
  • possible duplicate of [How to parse CSS font shorthand format](http://stackoverflow.com/questions/5618676/how-to-parse-css-font-shorthand-format) – stema Apr 13 '12 at 05:57

3 Answers3

8

Answering my own question:

/^\s*(?=(?:(?:[-a-z]+\s*){0,2}(italic|oblique))?)(?=(?:(?:[-a-z]+\s*){0,2}(small-caps))?)(?=(?:(?:[-a-z]+\s*){0,2}(bold(?:er)?|lighter|[1-9]00))?)(?:(?:normal|\1|\2|\3)\s*){0,3}((?:xx?-)?(?:small|large)|medium|smaller|larger|[.\d]+(?:\%|in|[cem]m|ex|p[ctx]))(?:\s*\/\s*(normal|[.\d]+(?:\%|in|[cem]m|ex|p[ctx])))?\s*([-,\"\sa-z]+?)\s*$/i

which separates to:

var       parts = rx.exec( str )
  , fontStyle   = parts[1] || 'normal'
  , fontVariant = parts[2] || 'normal'
  , fontWeight  = parts[3] || 'normal'
  , fontSize    = parts[4]
  , lineHeight  = parts[5]
  , fontFamily  = parts[6]
  ;

And yes, I realize that's insane

  • I'm not writing that beast for you but I'd look into back references for stuff that repeats a lot like the size units to trim it down a bit. – Erik Reppen Apr 13 '12 at 06:32
  • @ErikReppen -- I don't think I can compress it much more than it already is :) The size-units can't be back-referenced because `12px/30em verdana` is perfectly valid. –  Apr 13 '12 at 06:42
  • @ErikReppen -- scratch that, added back-references for the first 3 props :) –  Apr 13 '12 at 06:46
  • That's brilliant! A couple of quirky edge cases I found... You can specify, for example, italic three times for the three optional leading terms, and it won't complain. Haven't tried to see how browsers actually handle such a silly case. A more serious case is that special characters will break the font names section. In particular, a single quote (`'`), which is often used to enclose font names that have spaces. I'm not concerned about the other edge cases, but I am using a variant of your regex that also accepts a single quote inside the last group. – mo. Oct 10 '13 at 14:02
  • Isn't it supposed to support font-stretch after font-weight? https://developer.mozilla.org/en-US/docs/Web/CSS/font#font-variant-css21 – jedmao Jul 12 '15 at 06:38
  • @jedmao -- `font-stretch` is only supported by IE & FF. I generally don't care about features that aren't widely supported :) Especially in cases like this where including it will often cause browsers to ignore the _entire_ rule, so while FF & IE might support it in `font`, it's better to make it its own rule so that the other browsers don't ignore the `font` rule entirely. –  Jul 25 '15 at 01:59
  • and to separate simple fontsize, eg '10px' ? ; need in node, lodash maybe? – stackdave Sep 29 '17 at 16:38
  • @stackdave -- `10px` isn't a valid `font` value, chrome doesn't recognize it –  Sep 29 '17 at 19:43
3

you mean like this?

How to parse CSS font shorthand format

Alternatively, there is also JSCSSP, a JavaScript library for parsing CSS.

Community
  • 1
  • 1
zpea
  • 1,072
  • 6
  • 23
  • Can't use the accepted answer on that since this code runs in node.js sometimes so can't use dom-parsing. The answer further down might work, need to test it. –  Apr 13 '12 at 05:41
0

Just a little fix to support parsing fonts with numbers in the name, such as Font Awesome (ex. Font Awesome 5 Free).

This regex :

/^\s*(?=(?:(?:[-a-z]+\s*){0,2}(italic|oblique))?)(?=(?:(?:[-a-z]+\s*){0,2}(small-caps))?)(?=(?:(?:[-a-z]+\s*){0,2}(bold(?:er)?|lighter|[1-9]00))?)(?:(?:normal|\1|\2|\3)\s*){0,3}((?:xx?-)?(?:small|large)|medium|smaller|larger|[.\d]+(?:\%|in|[cem]m|ex|p[ctx]))(?:\s*\/\s*(normal|[.\d]+(?:\%|in|[cem]m|ex|p[ctx])))?\s*([-,\"\sa-z0-9]+?)\s*$/i

which separates to:

    var       parts = rx.exec( str )
  , fontStyle   = parts[1] || 'normal'
  , fontVariant = parts[2] || 'normal'
  , fontWeight  = parts[3] || 'normal'
  , fontSize    = parts[4]
  , lineHeight  = parts[5]
  , fontFamily  = parts[6]
  ;

just edit the block of fontFamily rules like ([-,"\sa-z0-9]+?)