0

I have an API returning the following string

styles: "background #2b2b2b; color: #FFFFFF"

I need to convert this on the fly into an object like so

styles: { background: '#2b2b2b', color: '#FFFFFF' }

How best to achieve this

Benni Russell
  • 354
  • 2
  • 7
  • doesnt seem like a valid CSS, but you can look for parser that can handle missing `:` https://stackoverflow.com/questions/3326494/parsing-css-in-javascript-jquery – Slai Sep 11 '18 at 14:07
  • 2
    This would be difficult to convert mainly because there doesn't seem to be a consistent pattern for separating keys and values. The key `background` is separated from the value `#2b2b2b` by a space, but the key `color` is separated from the value `#FFFFFF` by a colon and a space. If this was a typo and there is actually a colon after `background` then this would be doable if there's a guarantee that the string will always be valid css (i.e. the format will always be `key1: value1; key2: value2; key3: value3`) – Richard Pressler Sep 11 '18 at 14:08

3 Answers3

3

Please do some searching before asking. People are going to rate your question down now. But here's an answer anyway...

const str = "background #2b2b2b; color: #FFFFFF"
const obj = str.split('; ').reduce((acc, keyVal) => {
  const [key, val] = keyVal.split(' ')
  acc[key] = val
  return acc
}, {})

console.log(obj) // {background: "#2b2b2b", color:: "#FFFFFF"}

// if str was just 'background #2b2b2b;' it would include the ;
// {background: "#2b2b2b;"}

As someone mentioned your string is inconsistent so you'll need to fix the string format or add ways to handle edge cases.

Update: Perhaps a more flexible way would be to use RegExp. I'm not the best at writing RegExps so it could probably be improved.

// add acceptable characters in the brackets [ ]
const re = /([a-z-]+):\s?([()'"#a-z0-9]+);/gi

const str = 'background: #2b2b2b; color: #FFFFFF;background-url: url("test");'
const styles = {}

let next

while ((next = re.exec(str)) !== null) {
  const key = next[1]
  const value = next[2]
  // or const [ _, key, value ] = next

  styles[key] = value
}

console.log(styles)

/*
{
  background: '#2b2b2b',
  color: '#FFFFFF',
  'background-url': 'url("test")'
}
*/

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec

CodeDraken
  • 1,163
  • 6
  • 12
  • Just for the sake of adding something to the boilerplate, you should handle the case where there is more than one space, like: `border: 1px solid black` (the current behavior will return "border: 1px"). Also, beware that this syntax may not be compatible in all browsers, so it's worth mentioning that. You may change `const [key, val]` to : `const [key, ...val]`, then `acc[key] = val` to `acc[key] = val.join(' ')` – briosheje Sep 11 '18 at 14:19
  • Maybe if @Benjamin Russel clears up if it is just a typo you can split on `: `, because at the moment the object is not converted completely right (Note the extra `:` in the objects color key `color:: "#FFFFFF"`) – Daniel Habenicht Sep 11 '18 at 14:27
  • Good mentions +1. Yeah, he'll have to change the `split('; ')` to match whatever his input strings actually look like and maybe throw in a `.trim` – CodeDraken Sep 11 '18 at 15:03
1

Regular expression alternative https://regex101.com/r/ZmAW1m

var o = {}, s = "background #2b2b2b; color: #FFFFFF"

s.replace(/([^: ]+)[: ]+([^; ]+)[; ]*/g, (m, k, v) => o[k] = v)

console.log(o)
Slai
  • 22,144
  • 5
  • 45
  • 53
-1

You can convert

let styles = "background #2b2b2b; color: #FFFFFF";

into

stylesObj = {background: styles.split(";")[0].trim().split(" ")[1], 
                       color: styles.split(";")[1].trim().split(" ")[1]}

// {background: "#2b2b2b", color: "#FFFFFF"}

and you should get it in the form that you want.

EDIT

Added the .trim(), otherwise it does not work if the string has extra spaces.

hjbello
  • 643
  • 4
  • 18
  • I think a more general/dynamic solution might be better for this case. Just imagine that the key (e.g. `background`) might change or that there are multiple values as mentioned above by @briosheje. Also this tends to get unreadable as you are chaining the string operations. Furthermore you are executing the same operation twice (`styles.split(';')`) – Daniel Habenicht Sep 11 '18 at 14:35
  • Ok, that is fair. – hjbello Sep 11 '18 at 14:37