Function that converts this string to a json

Asked

Viewed 296 times

5

I have a string in the following format:

"a=123 b="ABC" c="Olá Mundo!""

need to create a function that transforms this string in this json:

{
    a : 123,
    b : "ABC",
    c : "Olá Mundo!"
}

I think it has a bit of regular expression and a split(), but I know almost nothing of Regex.

I was developing this function, but I wasn’t very successful.

    function strToJson(str) {
        var json = {};
        var str_split = str.split(" ");
        var str_split_value = [];

        for (var i in str_split) {
            str_split_value = str_split[i].split("=");
            json[str_split_value[0]] = str_split_value[1];
        }

        return json;
    }

    console.log(strToJson('a=123 b="ABC" c="Olá Mundo!"'));

  • 1

    If you have something you tried, some beginning code? Or just the problem itself?

  • My logic would be to split() the string separated by spaces, but this logic does not work very well in item c.

  • Then, but starts something...and sees where it sticks, then edits the question and puts your code... Num leva a mal, mai then will have more answers... And they’ll help you solve...

  • 1

    Although you have received a reply and are satisfied with it, this type of operation seems fundamentally problematic when using a data format without complete specification. Just to quote an example, what would happen if there were quotes inside a text? Before putting such code into production, always make sure it is not possible to write the data in a consistent format like JSON itself.

  • Of course I’m not going to put it into production, is that I’m very curious, and many of the questions I ask around here is just for knowledge.

Show 1 more comment

3 answers

5

var s = 'a=123 b="ABC" c="Olá Mundo!"';

var obj = {},
    parcial = '',
    inString = false,
    isProp = true,
    conteudo = '',
    prop = '';
for (i = 0; i < s.length; i++) { 
    var atual = s[i];

    if(atual=='"'){
        inString = !inString;
    }

    if((atual==' ')&&(!inString)){
        isProp=true;
        parcial='';
        obj[prop]=conteudo;
        continue;
    }
    if(atual == '='){
        isProp=false;
        parcial='';
        continue;
    }

    parcial += atual;
    if(isProp){
        prop=parcial;
    } else {
        conteudo=parcial;
    }

    if(i==s.length-1){
        obj[prop]=conteudo;
    }

    console.log('Atual: "'+atual+'"; Parcial: "'+parcial+'"; Prop:"'+prop+'"; Conteudo:"'+conteudo+'";');

}

console.log(obj);
  • 1

    Exactly what I needed! I just need to understand the logic of the code...

3

No split() or simple regular expression will do what you want. You need to develop a mini-interpreter, with state machine. Something like this (in pseudocode):

estado = 0;
nome = "";
valor = "";

// sentinela para terminar o parse dentro do loop
str += " ";

for (i = 0; i < str.length(); ++i) {
    // interpreta caractere por caractere
    c = str[i];
    if (estado === 0) {
        // estado: inicial
        c é espaço -> ignora
        c é letra -> estado := 1
                      nome := c
        c de outro tipo -> erro! 
    } else if (estado === 1) {
        // estado: acumulando nome 
        c é letra, número ou _ -> nome += c
        c é "=" -> estado := 2
        c é outro tipo -> erro!
    } else if (estado === 2) {
        // estado: = encontrado
        c é número -> valor := c
                      estado := 3
        c é aspa -> valor := c
                    estado := 4
        c é espaço -> ignora
        c é outra coisa -> erro! 
    } else if (estado === 3) {
        // estado: acumulando valor inteiro
        c é número -> valor += c
        c é espaço -> grava tupla (nome, parseInt(valor))
                      estado := 0
        c é outra coisa -> erro!
    } else if (estado === 4) {
        // estado: acumulando string 
        c é aspa -> grava tupla (nome, valor)
                    estado := 0
        c é qualquer outro caractere -> valor += c
    }
}

2


Everything is easier with REGEX.

([a-zA-Z_]\w*?)=(\d+|"[^"]*")( |$)

Explanation

([a-zA-Z_]\w*?)

Variable name part - Group 1

  • [a-zA-Z_] = will ensure that it starts with a letter or underline
  • \w*? = allows it to have more letters and numbers underline

(\d+|"[^"]*")

Part of the content - Group 2

  • \d+ = must capture numbers
  • | = OR wants to say that if the previous fails try the next
  • "[^"]*" = Must capture a " anything other than " and finally a " - a string

Part of the end - Group 3 (not useful for use)

  • ( |$) - Indicates that the content ends OR with  (space) OR (End of sentence, end of content)

Use

'a=123 b="ABC" c="Olá Mundo!"'.match(/([a-zA-Z_]\w*?)=(\d+|"[^"]*")( |$)/g)

See working in REGEX101

Browser other questions tagged

You are not signed in. Login or sign up in order to post.