skip to Main Content

I am trying to convert objects defined within a file into arrays.

I am using JSON.parse on the matched objects.

Some of the multi-line objects are not being replaced.

const txtara = document.querySelector('#demo');

const fixJSON = (invalidJson) => invalidJson
  .replace(/(w+)(?=s*:)/g, '"$1"') // Quote keys
  .replace(/,}/, '}')               // Remove stray commas
  .replace(/,ns*}/, '}');         // Remove stray commas (multiline)

const jsonObjectToArray = (jsonObject) => {
  const obj = JSON.parse(fixJSON(jsonObject));
  return JSON.stringify(Object.values(obj));
}

let content = txtara.value
  // Inline object
    .replace(/({(.+)})/g, (match, json) => jsonObjectToArray(json))
  // Multi-line object
    .replace(/({s*n(?:s*w+s*:s*.+,?n)+s*})/, (match, json) => jsonObjectToArray(json));

txtara.value = content;
*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body {
  width: 100%;
  height: 100%;
  padding: 0;
  margin: 0;
}

body {
  display: flex;
}

#demo {
  flex: 1;
  resize: none;
  color: #EEE;
  background: #222;
  padding: 0.5rem;
}
<textarea id="demo">
{x:1,y:2}
{x:1,y:2,z:3}
{x:1,y:2,z:3,}
{ x: 1, y: 2, z: 3 }
{
  x: 1,
  y: 2,
}
{
  x: 1,
  y: 2
}
{
  x: 1,
  y: 2,
  z: 3
}
{
  x: 1,
  y: 2,
  z: 3,
}
</textarea>

2

Answers


  1. If you need only numbers, then your answer is

    function textToNumberArrays(text) {
      return text.match(/{[^}]}/g) // match {...}
        .map(obj => {
          return obj.match(/d+(.d+)?/g) // match 123 and 123.456
            .map(n => Number(n)) // convert match strings to numbers
        })
    }
    
    Login or Signup to reply.
  2. You can use eval() and a sliding window that you expand whenever eval() throws an error:

    const textarea = document.getElementById('textarea')
    
    const parseButton = document.getElementById('parseButton')
    
    parseButton.addEventListener('click', () => {
      const parts = textarea.value.split('n');
      const parsed = [];
      
      let from = 0;
      let to = 0;
      let n = 1; 
      
      while (from < parts.length && to <= parts.length) {
        try {
          to = from + n;
          
          const parsedPart = eval(`(${ parts.slice(from, to).join('') })`)
          
          parsed.push(parsedPart);
          
          from = to;      
          n = 1;
        } catch (err) {
          ++n;
        }
      }
      
      console.log(`${ parsed.length } objects found = `, parsed);
    })
    body {
      display: flex;
      flex-direction: column;
      margin: 8px;
    }
    
    #textarea {
      display: block;
      width: 100%;
      height: calc(100vh - 56px);
      resize: none;
      flex: 1 0 auto;
      box-sizing: border-box;
    }
    
    #parseButton {
      height: 32px;
      margin-top: 8px;
    }
    <textarea id="textarea">
    {x:1,y:2}
    {x:1,y:2,z:3}
    {x:1,y:2,z:3,}
    { x: 1, y: 2, z: 3 }
    {
      x: 1,
      y: 2,
    }
    {
      x: 1,
      y: 2
    }
    {
      x: 1,
      y: 2,
      z: 3
    }
    {
      x: 1,
      y: 2,
      z: 3,
    }
    </textarea>
    
    <button id="parseButton">Parse</button>

    But keep in mind eval should only be used in trusted environments:

    Warning: Executing JavaScript from a string is an enormous security risk. It is far too easy for a bad actor to run arbitrary code when you use eval().

    See Never use eval()!.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search