2014-09-25 3 views
0

Приносим извинения за задание этого вопроса таким образом, но, по-видимому, мне недостаточно «репутации», чтобы опубликовать вопрос в качестве комментария в исходной теме.Редактирование JsonHelper

Кто-то here сделал приятный небольшой класс, чтобы правильно отстроить строку JSON, чтобы она была удобнее для людей. Он отлично работает, за исключением того, что я хотел бы изменить его так, чтобы пустые массивы были представлены как «[]», а не имели кучу пробелов между символами (новая строка, вероятно, несколько символов отступа и т. Д.). Казалось, такой простой план.

Исходный код выглядит следующим образом:

private const string INDENT_STRING = " "; 
    public static string FormatJson(string str) 
    { 
     var indent = 0; 
     var quoted = false; 
     var sb = new StringBuilder(); 
     for (var i = 0; i < str.Length; i++) 
     { 
       var ch = str[i]; 
       switch (ch) 
       { 
        case '{': 
        case '[': 
         sb.Append(ch); 
         if (!quoted) 
         { 
          sb.AppendLine(); 
          Enumerable.Range(0, ++indent).ForEach(item => sb.Append(INDENT_STRING)); 
         } 
         break; 
        case '}': 
        case ']': 
         if (!quoted) 
         { 
          sb.AppendLine(); 
          Enumerable.Range(0, --indent).ForEach(item => sb.Append(INDENT_STRING)); 
         } 
         sb.Append(ch); 
         break; 
        case '"': 
         sb.Append(ch); 
         bool escaped = false; 
         var index = i; 
         while (index > 0 && str[--index] == '\\') 
          escaped = !escaped; 
         if (!escaped) 
          quoted = !quoted; 
         break; 
        case ',': 
         sb.Append(ch); 
         if (!quoted) 
         { 
          sb.AppendLine(); 
          Enumerable.Range(0, indent).ForEach(item => sb.Append(INDENT_STRING)); 
         } 
         break; 
        case ':': 
         sb.Append(ch); 
         if (!quoted) 
          sb.Append(" "); 
         break; 
        default: 
         sb.Append(ch); 
         break; 
       } 
     } 
     return sb.ToString(); 
    } 

Я попытался изменить его, так что было это в нем:

    case '[': 
         sb.Append(ch); 
         if (!quoted) 
         { 
          if (str[i + 1] != ']') 
          { 
           sb.AppendLine(); 
           Enumerable.Range(0, ++indent).ForEach(item => sb.Append(INDENT_STRING)); 
          } 
         } 
         break; 

Дует на меня, жалуясь, что я ссылки индекс это слишком велико (на самом деле он жалуется на то, что имеет ряд возможностей, скорее всего, «ArgumentOutOfRangeException» ). Я попытался добавить трекер, чтобы узнать, есть ли i+1 > str.Length, но он все еще взрывается. И место в струне, в которую он взорвался, не находится рядом с [ или ]. Действительно, ch является «{» и str[i+1] является «,».

Имею ли я смысл?

Я думал о том, чтобы просто взять результирующую строку и использовать Regex, чтобы вырвать любые пробелы между [и], но это казалось неэлегантным.

Есть ли у кого-нибудь рекомендации по изменению этого в противном случае-отличного кода так, как я хочу? Я пробовал, действительно я это сделал ...

ответ

0

Я использовал другой подход. Когда я сталкиваюсь с квадратной скобкой, я проверяю, где находится квадратная скобка спаривания, и проверьте, что между ними нет пустой строки. Выражение это:

isEmptyArray = nextMatchingBracketIndex != -1 ? stringRemainder.Substring(1, nextMatchingBracketIndex - 1).Trim().Length == 0 : false; 

полный рабочий код:

class JsonHelper 
    { 
     private const string INDENT_STRING = " "; 
     public static string FormatJson(string str) 
     { 
      var indent = 0; 
      var quoted = false; 
      var isEmptyArray = false; 
      var sb = new StringBuilder(); 
      char ch = default(char); 

      for (var i = 0; i < str.Length; i++) 
      { 
       ch = str[i]; 

       switch (ch) 
       { 
        case '{': 
         sb.Append(ch); 
         if (!quoted) 
         { 
          sb.AppendLine(); 
          Enumerable.Range(0, ++indent).ForEach(item => sb.Append(INDENT_STRING)); 
         } 
         break; 
        case '[': 
         sb.Append(ch); 

         var stringRemainder = str.Substring(i); 
         var nextMatchingBracketIndex = stringRemainder.IndexOf(']'); 

         isEmptyArray = nextMatchingBracketIndex != -1 ? stringRemainder.Substring(1, nextMatchingBracketIndex - 1).Trim().Length == 0 : false; 

         if (!quoted && !isEmptyArray) 
         { 
          sb.AppendLine(); 
          Enumerable.Range(0, ++indent).ForEach(item => sb.Append(INDENT_STRING)); 
         } 
         break; 
        case '}': 
         if (!quoted) 
         { 
          sb.AppendLine(); 
          Enumerable.Range(0, --indent).ForEach(item => sb.Append(INDENT_STRING)); 
         } 
         sb.Append(ch); 
         break; 
        case ']': 
         if (!quoted && !isEmptyArray) 
         { 
          sb.AppendLine(); 
          Enumerable.Range(0, --indent).ForEach(item => sb.Append(INDENT_STRING)); 
         } 
         sb.Append(ch); 
         isEmptyArray = false; 
         break; 
        case '"': 
         sb.Append(ch); 
         bool escaped = false; 
         var index = i; 
         while (index > 0 && str[--index] == '\\') 
          escaped = !escaped; 
         if (!escaped) 
          quoted = !quoted; 
         break; 
        case ',': 
         sb.Append(ch); 
         if (!quoted) 
         { 
          sb.AppendLine(); 
          Enumerable.Range(0, indent).ForEach(item => sb.Append(INDENT_STRING)); 
         } 
         break; 
        case ':': 
         sb.Append(ch); 
         if (!quoted) 
          sb.Append(" "); 
         break; 
        default: 
         if (!isEmptyArray) 
          sb.Append(ch); 
         break; 
       } 
      } 
      return sb.ToString(); 
     } 
    } 

Вот тест, который я проверить работу, как и ожидалось:

  1. Empty типа массива:

    "types":[] 
    
  2. Пустых типов массив символов между:

    "types":[  ] 
    
  3. Полных типами массива с пустыми символами в начале

    "types":[ "locality", "political"] 
    

нота: в 1,2,3 я отношусь к подстрока в исходном файле JSON, указанная в вашей ссылке:

{"status":"OK", "results":[ {"types":[ "locality", "political"], "formatted_address":"New York, NY, USA", "address_components":[ {"long_name":"New York", "short_name":"New York", "types":[ "locality", "political"]}, {"long_name":"New York", "short_name":"New York", "types":[ "administrative_area_level_2", "political"]}, {"long_name":"New York", "short_name":"NY", "types":[ "administrative_area_level_1", "political"]}, {"long_name":"United States", "short_name":"US", "types":[ "country", "political"]}], "geometry":{"location":{"lat":40.7143528, "lng":-74.0059731}, "location_type":"APPROXIMATE", "viewport":{"southwest":{"lat":40.5788964, "lng":-74.2620919}, "northeast":{"lat":40.8495342, "lng":-73.7498543}}, "bounds":{"southwest":{"lat":40.4773990, "lng":-74.2590900}, "northeast":{"lat":40.9175770, "lng":-73.7002720}}}}]} 

I h ave проверил выход, который я получил в разных тестах с JSONLint, и это было действительно.

Это 1 час утра, и я уверен, что есть какой-то край, который я не закрыл. Но этот код должен дать вам альтернативный подход, который работает лучше, чем то, что у вас есть прямо сейчас.

+0

Это сработало отлично, спасибо. –

Смежные вопросы