Pergunta

Eu estou tentando analisar uma série de objetos JSON em uma matriz de strings em C #. Posso extrair a matriz do objeto JSON, mas não posso dividir a string array em uma matriz de objetos individuais.

O que eu tenho é esta cadeia de teste:

string json = "{items:[{id:0,name:\"Lorem Ipsum\"},{id:1,name" 
            + ":\"Lorem Ipsum\"},{id:2,name:\"Lorem Ipsum\"}]}";

Agora eu estou usando as seguintes expressões regulares agora para dividir os itens em objetos individuais. Por enquanto eles estão 2 expressões regulares separadas até eu resolver o problema com a segunda:

Regex arrayFinder = new Regex(@"\{items:\[(?<items>[^\]]*)\]\}"
                                 , RegexOptions.ExplicitCapture);
Regex arrayParser = new Regex(@"((?<items>\{[^\}]\}),?)+"
                                 , RegexOptions.ExplicitCapture);

O regex arrayFinder funciona da maneira que eu esperava, mas, por razões que eu não entendo, o regex arrayParser não funciona em todos. Tudo o que eu quero fazer é dividir os itens individuais em suas próprias cordas assim que eu conseguir uma lista como esta:

{id:0,name:"Lorem Ipsum"}
{id:1,name:"Lorem Ipsum"}
{id:2,name:"Lorem Ipsum"}

Se esta lista é uma matriz string[] ou um Group ou cobrança Match não importa, mas estou perplexo a respeito de como obter a divisão objetos. Usando o arrayParser ea cadeia json declaradas acima, eu tentei este código, que eu assumi iria trabalhar sem sorte:

string json = "{items:[{id:0,name:\"Lorem Ipsum\"},{id:1,name" 
            + ":\"Lorem Ipsum\"},{id:2,name:\"Lorem Ipsum\"}]}";

Regex arrayFinder = new Regex(@"\{items:\[(?<items>[^\]]*)\]\}"
                                 , RegexOptions.ExplicitCapture);
Regex arrayParser = new Regex(@"((?<items>\{[^\}]\}),?)+"
                                 , RegexOptions.ExplicitCapture);

string array = arrayFinder.Match(json).Groups["items"].Value;
// At this point the 'array' variable contains: 
// {id:0,name:"Lorem Ipsum"},{id:1,name:"Lorem Ipsum"},{id:2,name:"Lorem Ipsum"}

// I would have expected one of these 2 lines to return 
// the array of matches I'm looking for
CaptureCollection c = arrayParser.Match(array).Captures;
GroupCollection g = arrayParser.Match(array).Groups;

Alguém pode ver o que é que estou fazendo errado? Estou totalmente preso sobre isso.

Foi útil?

Solução

parênteses balanceados são literalmente um exemplo clássico de uma língua que não pode ser processado com expressões regulares. JSON é essencialmente equilibrado parênteses mais um monte de outras coisas, com as chaves substituídas por parênteses. No de linguagens formais hierarquia , JSON é uma linguagem livre de contexto. expressões regulares não pode analisar linguagens livres de contexto.

Alguns sistemas oferecem extensões para expressões regulares que pega meio-sorta expressões equilibrada. No entanto todos eles são hacks feios, eles são todos portável, e todos eles são em última análise, a ferramenta errada para o trabalho.

No trabalho profissional, você quase sempre usar um analisador JSON existente. Se você desejar construir sua própria para fins educacionais, então eu sugiro começar com uma gramática aritmética simples que suporta + - * / (). (JSON tem algumas regras de escape que, embora não complexa, vai fazer a sua primeira tentativa mais difícil do que precisa ser.) Basicamente, você vai precisar:

  1. Decompose a língua em um alfabeto de símbolos
  2. Escreva uma gramática livre de contexto em termos de esses símbolos thatrecognizes a linguagem
  3. Converter a gramática na forma normal de Chomsky, ou perto o suficiente para fazer a etapa 5 fácil
  4. Escrever um lexer que converte texto bruto em sua entrada alfabeto
  5. Escrever um analisador descendente recursivo que leva saída do seu lexer, analisa-lo, e produz algum tipo de saída

Este é um terceiro ano de atribuição típica CS em praticamente qualquer universidade.

O próximo passo é descobrir o quão complexa uma string JSON que você precisa para desencadear um estouro de pilha em sua parser recursivo. Então olha para os outros tipos de analisadores que podem ser escritas, e você vai entender por que quem tem de analisar uma linguagem livre de contexto no mundo real usa uma ferramenta como yacc ou antlr em vez de escrever um analisador com a mão.

Se isso é mais aprender do que você estava procurando, então você deve se sentir livre para ir usar um analisador off-the-shelf JSON, satisified que você aprendeu algo importante e útil:. Os limites de expressões regulares

Outras dicas

parênteses balanceados são, literalmente, um exemplo clássico de uma língua que não pode ser processado com expressões regulares

bla bla bla ... veja isso:

arrayParser = "(?<Key>[\w]+)":"?(?<Value>([\s\w\d\.\\\-/:_]+(,[,\s\w\d\.\\\-/:_]+)?)+)"?

Isso funciona para mim

Se você quiser combinar valores vazios mudar última '+' para '*'

Você está usando .NET 3.5? Se assim for, você pode usar o DataContractJsonSerializer para analisar isso. Não há nenhuma razão para fazer isso sozinho.

Se você não estiver usando .NET 3.5, você pode usar Jayrock .

public Dictionary<string, string> ParseJSON(string s)
{
    Regex r = new Regex("\"(?<Key>[\\w]*)\":\"?(?<Value>([\\s\\w\\d\\.\\\\\\-/:_\\+]+(,[,\\s\\w\\d\\.\\\\\\-/:_\\+]*)?)*)\"?");
    MatchCollection mc = r.Matches(s);

    Dictionary<string, string> json = new Dictionary<string, string>();

    foreach (Match k in mc)
    {
        json.Add(k.Groups["Key"].Value, k.Groups["Value"].Value);

    }
    return json;
}

Esta função implementar Lukasz expressão regular. Eu só adicionar à inclide + char para grupo valor (porque eu estou usando isso para analisar token de autenticação de conexão ao vivo)

JSON não pode normalmente ser analisado com expressões regulares (certas variantes extremamente simplificados de JSON pode, mas então eles não são JSON mas outra coisa).

Você precisa de um analisador real para JSON adequadamente análise.

E de qualquer maneira, por que você está tentando analisar JSON em tudo? Existem inúmeras bibliotecas lá fora que pode fazer isso por você, e muito melhor do que o seu código faria. Por que reinventar a roda, quando há uma fábrica de roda em torno do canto com as palavras FOSS sobre a porta?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top