Home > Back-end >  How to split text into key-pair value in JavaScript?
How to split text into key-pair value in JavaScript?

Time:04-19

I have received result from Raspberry Pi as Text format and I want to use these text to insert into MongoDB as key-pair value or JSON for my Node.js Application. However, I am quite new with JavaScript and trying to figure out the solution. Please help me if you have any suggestion, Thank you very much.

Example:

//Text from Raspberry Pi

1, 2300,450
2, 2200, 920
3, 3400, 440

and I want it to be

[
 {
  person: 1,
  x position: 2300,
  y position: 450
 }, 
 {
  person: 2,
  x position: 2200,
  y position: 920
 }, 
 {
  person: 3,
  x position: 3400,
  y position: 440
 }
] 

CodePudding user response:

You can first create array from the text by using split method and then convert the input array to the array of the object

  1. Split on new line character /n to get the lines
  2. Split on the comma and space , to get all the elements
  3. Loop over the array and convert array element to object

Code snippet

let input = `1, 2300, 450
2, 2200, 920
3, 3400, 440`;

let linesArr = input.split(/\n/);
let elArray = linesArr.map((line) => line.split(', '))
let result = elArray.map((el) => {
  return {
    "person": parseInt(el[0]),
    "x_position": parseInt(el[1]),
    "y_position": parseInt(el[2])
  }
})
console.log(result)

CodePudding user response:

You can transform your string into an array, use an array to store the exact name of your keys and then through .reduce create your new array.

const input = '1, 2300, 450, 2, 2200, 920, 3, 3400, 440';
const keys = ['person', 'x position', 'y position'];
let obj = {};
let counter = 0;

const result = input.split(',').reduce((acc, x) => {
  obj[keys[counter]] = x.trim();
  counter  
  if (counter % 3 === 0) {
    acc.push(obj)
    counter = 0;
    obj = {};
  }
  return acc;
}, [])

console.log(result)

CodePudding user response:

Use split and map

let txt = `
1, 2300,450
2, 2200, 920
3, 3400, 440`;
let split = txt.split(/\n/);
let filter = split.filter(e => e != '');
let map = filter.map(function(f1) {
   let obj = {}
   obj['person'] = parseInt(f1.split(',')[0].trim(), 10); 
   obj['x position'] = parseInt(f1.split(',')[1].trim(), 10); 
   obj['y position'] = parseInt(f1.split(',')[2].trim(), 10); 
   return obj;
});
console.log(map);

CodePudding user response:

const fs = require("fs");

let data = fs.readFileSync("fs.txt", 'utf8');

let splitedData = data.split(",");
let final = [];
let person = splitedData[0];
let length = splitedData.length;
console.log(splitedData);
for(i=1;i<length; i=i 2){
    let yposper;
    let xposition = splitedData[i];
    let yposition;
    if(i!=(length-2)){
        yposper = splitedData[i 1].split("\r\n");
        yposition = yposper[0];
    } else{
        yposition = splitedData[i 1];
    }
    final.push({
        person: person,
        xposition: xposition.trim(),
        yposition: yposition.trim()
    });
    person = i!=(length-2) ? yposper[1] : null;
}

console.log(final);

Try here

CodePudding user response:

My own suggestion would be:

// creating a named function, as a constant, since the function isn't
// expected to be modified by code; this function is defined using
// Arrow syntax, and passes in the Event Object - from the (later)
// use of EventTarget.addEventListener() - to the function body:
const getResults = (evt) => {
    // here we retrieve the element to which the function was bound
    // with EventTarget.addEventListener():
    let button = evt.currentTarget,
      // from the <button> element we navigate - with Element.closest()
      // to the closest ancestor-element that matches the supplied CSS
      // selector; note that if no such element is found then this
      // will return null. So if you can't be sure the element will
      // exist, sanity-check the variable before use:
      ancestor = button.closest('li'),
      // from the ancestor we retrieve the <textarea> element, using
      // Element.querySelector(), which finds the first element
      // inside of the ('ancestor', <li>) Element that matches the
      // selector; again: if no such element is found, this will
      // return null:
      textarea = ancestor.querySelector('textarea'),
      // this is my habitual practice, but effectively we try to
      // retrieve the value property of the <textarea> element, if
      // that doesn't have a value, or returns a falsey value,
      // we retrieve the text-content instead:
      entry = textarea.value || textarea.textContent,
      // here we split the value/text-content on new-line characters,
      // using String.protoype.split() and passing in a regular
      // expression literal (/<regex sequence>/); which returns an
      // Array. We then use Array.prototype.reduce() to return a new
      // Array based on the passed-in Array:
      result = entry.split(/\n/).reduce(
        // here we pass in the accumulator ('acc', the Array we're working
        // to produce on each iteration through this Array) and the
        // Array-entry ('curr'):
        (acc, curr) => {
          // here we split the current ('curr') Array-value which is a String,
          // again using String.prototype.split() and a regular expression-literal;
          // this regular expression matches a comma followed by zero-or-more white-
          // space characters (tabs, space, etc...); we expect this String to return
          // a three part Array and we know the order; so we can use destructuring
          // assignment to define person as equal to the first Array-element,
          // posX to the second and posY to the third. If there are more
          // Array elements returned those will be unallocated:
          let [person, posX, posY] = curr.split(/,\s*/);
          // I can't remember the term for this, but it's effectively a shorthand;
          // but we use Array.prototype.push() to add an Object to the
          // accumulator Array; this Object passes in the variables and those variables
          // become both the name of the property (so the variable 'person' becomes both
          // the property 'person' and sets the value of that property to the value of
          // the variable):
          acc.push({
            person,
            posX,
            posY,
          });
          // we return the accumulator to continue working on it in the next iteration:
          return acc;
        // and here we pass in an empty Array-literal to act as the accumulator:
        }, []);
    // logging the result to the console:
    console.log(result);
  },
  // here we find all <button> elements with a 'type' attribute equal to 'button', using
  // document.querySelectorAll() to obtain a NodeList:
  buttons = document.querySelectorAll('button[type=button]');

// here we use NodeList.prototype.forEach() to iterate over the <button> elements:
buttons.forEach(
  // passing in a reference to the current Node of the NodeList over which we're iterating
  // to the Arrow function-body, and using EventTarget.addEventListener() to bind the
  // getResults() function as the event-handler for the 'click' event, this also passes
  // the Event Object to the named function:
  (btn) => btn.addEventListener('click', getResults)
);
*,
::before,
::after {
  box-sizing: border-box;
  font-family: sans-serif;
  font-size: 16px;
  font-weight: 400;
  line-height: 1.5;
  margin: 0;
  padding: 0;
}

ul,
li {
  list-style-type: none;
  padding: 1em;
}

li {
  display: flex;
  flex-direction: column;
  gap: 0.5em;
  justify-content: space-between;
}

textarea {
  min-height: 40vmin;
  width: 100%;
}
<ul>
  <li >
    <textarea>1, 2300,450
2, 2200, 920
3, 3400, 440</textarea>
    <button type="button">format</button>
  </li>
</ul>

JS Fiddle demo.

This, of course, relies upon the result being returned from the Pi with each entry on a new line; if this can't be guaranteed, or the Pi returns entries in a String without new-lines, the following may be preferred:

// this is much the same as above, except that we have no line-separators (though this
// may not be relevant to your situation):
const getResults = (evt) => {
    let button = evt.currentTarget,
      ancestor = button.closest('li'),
      textarea = ancestor.querySelector('textarea'),
      entry = textarea.value || textarea.textContent,
      // here we split the retrieved value/text-content of the <textarea> on the ','
      // (comma) characters; and then iterate over the returned Array using an
      // Arrow function, to trim any leading, and/or trailing, white-space from
      // each Array entry:
      haystack = entry.split(/,/).map((v) => v.trim()),
      // here we use Array.prototype.reduce() to create the Array to return:
      result = haystack.reduce(
        // we again use the accumulator ('acc'), and the current ('curr') array-value,
        // but we also pass in the index of the current Array-element:
        (acc, curr, index) => {
          // if the remainder left after dividing the current index by 3 is
          // exactly 0 (true for 0, 3, 6, 9...):
          if (index % 3 === 0) {
            // we use destructuring assignment to assign the named
            // variables ('person', 'posX', 'posY') to the result of
            // calling Array.splice() on a copy of the 'haystack'
            // Array (copied using spread syntax ('...') and an Array-literal
            // ('[]'); this removes n (here, 3) elements from the copy, starting at
            // the Array index 'index', and returns the removed Array elements:
            let [person, posX, posY] = [...haystack].splice(index, 3);
            // here we - again - push an Object, defined using the same shorthand
            // as above, to the accumulator Array:
            acc.push({
              person,
              posX,
              posY
            });
          }
          return acc
        }, []);
    // loggin the result variable:
    console.log(result);
  },
  buttons = document.querySelectorAll('button[type=button]');

buttons.forEach(
  (btn) => btn.addEventListener('click', getResults)
);
*,
::before,
::after {
  box-sizing: border-box;
  font-family: sans-serif;
  font-size: 16px;
  font-weight: 400;
  line-height: 1.5;
  margin: 0;
  padding: 0;
}

ul,
li {
  list-style-type: none;
  padding: 1em;
}

li {
  display: flex;
  flex-direction: column;
  gap: 0.5em;
  justify-content: space-between;
}

textarea {
  min-height: 40vmin;
  width: 100%;
}
<ul>
  <li >
    <textarea>1, 2300,450, 2, 2200, 920,3, 3400, 440</textarea>
    <button type="button">format</button>
  </li>
</ul>

JS Fiddle demo.

References:

  • Related