Есть ли способ красиво распечатать словари Swift на консоли?

92
NSDictionary *dictionary = @{@"A" : @"alfa",
                             @"B" : @"bravo",
                             @"C" : @"charlie",
                             @"D" : @"delta",
                             @"E" : @"echo",
                             @"F" : @"foxtrot"};
NSLog(@"%@", dictionary.description);

выводит на консоль следующее:

{
    A = alfa;
    B = bravo;
    C = charlie;
    D = delta;
    E = echo;
    F = foxtrot;
}

let dictionary: [String : String] = ["A" : "alfa",
                                     "B" : "bravo",
                                     "C" : "charlie",
                                     "D" : "delta",
                                     "E" : "echo",
                                     "F" : "foxtrot"];
print(dictionary)

выводит на консоль следующее:

["B": "bravo", "A": "alfa", "F": "foxtrot", "C": "charlie", "D": "delta", "E": "echo"]

Есть ли в Swift способ заставить его красиво печатать словари, где каждая пара ключ-значение занимает новую строку?

Толанд Хон
источник
7
Вы можете использовать dump, например, если цель - проверить словарь. stackoverflow.com/documentation/swift/3966/logging-in-swift/…
Эрик Айя,
13
print(dictionary as! NSDictionary) дешевый трюк?
BaseZen
Я действительно предлагаю dump (), поскольку он не требует написания кода или его преобразования. @EricAya, если вы опубликуете ответ с этим замечанием, я отмечу его как ответ.
Толанд Хон
1
@TolandHon Done. Я дал ответ на примере вывода.
Эрик Айя,

Ответы:

99

Вы можете использовать дамп , например, если хотите проверить словарь. dumpявляется частью стандартной библиотеки Swift.

Применение:

let dictionary: [String : String] = ["A" : "alfa",
                                     "B" : "bravo",
                                     "C" : "charlie",
                                     "D" : "delta",
                                     "E" : "echo",
                                     "F" : "foxtrot"]

dump(dictionary)

Выход:

введите описание изображения здесь


dump печатает содержимое объекта через отражение (зеркальное отображение).

Детальный вид массива:

let names = ["Joe", "Jane", "Jim", "Joyce"]
dump(names)

Печать:

▿ 4 элемента
- [0]: Джо
- [1]: Джейн
- [2]: Джим
- [3]: Джойс

Для словаря:

let attributes = ["foo": 10, "bar": 33, "baz": 42]
dump(attributes)

Печать:

▿ 3 пары ключ / значение
▿ [0]: (2 элемента)
- .0: bar
- .1: 33
▿ [1]: (2 элемента)
- .0: baz
- .1: 42
▿ [2]: ( 2 элемента)
- .0: foo
- .1: 10

dumpобъявлен как dump(_:name:indent:maxDepth:maxItems:).

Первый параметр не имеет метки.

Доступны и другие параметры, например, nameустановка метки для проверяемого объекта:

dump(attributes, name: "mirroring")

Печать:

▿ зеркальное отображение: 3 пары ключ / значение
▿ [0]: (2 элемента)
- .0: bar
- .1: 33
▿ [1]: (2 элемента)
- .0: baz
- .1: 42
▿ [2] : (2 элемента)
- .0: foo
- .1: 10

Вы также можете выбрать печать только определенного количества элементов maxItems:, анализ объекта до определенной глубины maxDepth:и изменение отступа печатаемых объектов с помощью indent:.

Эрик Айя
источник
5
Это не очень печатный JSON, это просто выгрузка переменной в консоль - недействительный JSON. Хотя это соответствует потребностям OP, я считаю, что вопрос необходимо переформулировать, чтобы соответствовать этому.
Джеймс Вулф
4
@JamesWolfe This is not pretty printed JSONНикто не сказал, что это было. OP спросил о хороших словарях Swift - никто не говорит о JSON, за исключением нескольких респондентов, не относящихся к теме. Вопрос OP вообще не касается JSON.
Эрик Айя
@JamesWolfe Также не меняйте вопрос. Это было бы вандализмом. Вопрос ясен как есть, и дело не в JSON. Не меняйте вопрос только потому, что некоторые ответы говорят о другом. Спасибо.
Эрик Айя
112

Преобразование словаря в AnyObject было для меня самым простым решением:

let dictionary = ["a":"b",
                  "c":"d",
                  "e":"f"]
print("This is the console output: \(dictionary as AnyObject)")

это вывод консоли

Для меня это легче читать, чем вариант дампа, но учтите, что он не даст вам общего количества пар "ключ-значение".

Джалаку
источник
11
Это блестящий способ и намного лучше, чем дамп,
Абдель Хади 01
109

ПО решение

Для тех из вас, кто хочет видеть словарь как JSON без escape-последовательности в консоли , вот простой способ сделать это

(lldb)p print(String(data: try! JSONSerialization.data(withJSONObject: object, options: .prettyPrinted), encoding: .utf8 )!)

Иршад Мохамед
источник
1
Поскольку это выражение, а не объект, оно должно быть «p», а не «po». Но большое спасибо за это решение! У меня отлично работает
Алессандро Франкуччи 06
@AlessandroFrancucci имеет значение? В любом случае команда, похоже, делает то же самое.
nickjwallin 09
Теперь работают оба способа. Но раньше делать «po print» у меня не получалось. (po означает объект печати .... что немного сбивает с толку, если у вас есть печать после этого, а не объект imho)
Алессандро Франкуччи
Потрясающие! как раз то, что мне нужно было красиво распечатать userInfo из PushNotification
carmen_munich
Отметьте этот комментарий, чтобы использовать его в псевдониме lldb, чтобы вам не приходилось вводить его каждый раз!
Agirault
36

Еще один способ использования функционального программирования

dictionary.forEach { print("\($0): \($1)") }

Выход

B: bravo
A: alfa
F: foxtrot
C: charlie
D: delta
E: echo
Лука Анджелетти
источник
1
Это должен быть главный ответ. Прекрасно работает!
Юрий Дубов
Или, чтобы быть «еще более функциональным» ... dictionary.map {"($ 0): ($ 1)"} .forEach (print) (насмешливый комментарий)
Джон Уиллис,
3
Это работает для [String: String]словаря OP , но не [AnyHashable: Any]подходит для словарей, где, если значение является словарем, вы вернетесь к некрасивой печати Swift.
Кристофер Пикслей,
У меня есть книга, помеченная этим ответом 🙂, потому что я до сих пор не могу вспомнить этот синтаксис N
Нитин Алабур
29

Только для целей отладки я бы преобразовал массив или словарь в довольно печатный json:

public extension Collection {

    /// Convert self to JSON String.
    /// Returns: the pretty printed JSON string or an empty string if any error occur.
    func json() -> String {
        do {
            let jsonData = try JSONSerialization.data(withJSONObject: self, options: [.prettyPrinted])
            return String(data: jsonData, encoding: .utf8) ?? "{}"
        } catch {
            print("json serialization error: \(error)")
            return "{}"
        }
    }
}

Затем:

print("\nHTTP request: \(URL)\nParams: \(params.json())\n")

Результат на консоли:

HTTP request: https://example.com/get-data
Params: {
  "lon" : 10.8663676,
  "radius" : 111131.8046875,
  "lat" : 23.8063882,
  "index_start" : 0,
  "uid" : 1
}
Марко М
источник
что здесь bLog?
Nitesh
@Nitesh bLog - это простой пользовательский логгер с обратной трассировкой, который я написал, отредактированный с помощью print ().
Marco M
Красивейшее решение.
Денис Кутлубаев
Если вы не хотите добавлять этот фрагмент кода в каждый из ваших проектов, вы можете использовать этот код с псевдонимом lldb, чтобы легко вычислить json в терминале отладки (подробности здесь ).
Agirault
14

Я бы не стал рассматривать многие ответы, представленные здесь, как истинный, довольно печатный JSON, поскольку, когда вы передаете результаты в валидатор JSON, результат недействителен (часто из-за кода, включающего '=', а не ':').

Самый простой способ, который я нашел для этого, - это просто преобразовать объект JSON в данные с помощью красивой печатной опции записи, а затем распечатать строку с использованием полученных данных.

Вот пример:

let jsonData = try! JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted)

if let jsonString = String(data: jsonData, encoding: .utf8) {
    print(jsonString)
}

Результат:

{
    "jsonData": [
        "Some String"
    ],
    "moreJSONData": "Another String",
    "evenMoreJSONData": {
        "A final String": "awd"
    }
}

РЕДАКТИРОВАТЬ : было указано, что OP не запрашивал JSON, однако я считаю, что ответы, рекомендующие просто распечатать или выгружать данные в консоль, обеспечивают очень небольшое форматирование (если таковое имеется) и, следовательно, не очень печатаются.

Я считаю, что, несмотря на то, что OP не запрашивает JSON, это жизнеспособный ответ, поскольку это гораздо более читаемый формат для данных, чем ужасный формат, который выводится в консоль с помощью xcode / swift.

Джеймс Вулф
источник
1
Спасибо, с этим я смог e let jsonData = try! JSONSerialization.data(withJSONObject: response, options: .prettyPrinted);if let jsonString = String(data: jsonData, encoding: .utf8) { print(jsonString) }
хорошо
1
Это круто! Вы можете использовать этот код с псевдонимом lldb, чтобы легко вычислить json в терминале отладки (подробности здесь ).
Agirault
5

Вы можете просто использовать цикл for и печатать каждую итерацию

for (key,value) in dictionary { 
    print("\(key) = \(value)")
}

Приложение в расширении:

extension Dictionary where Key: CustomDebugStringConvertible, Value:CustomDebugStringConvertible {

    var prettyprint : String {
        for (key,value) in self {
            print("\(key) = \(value)")
        }

        return self.description
    }
}

Альтернативное приложение:

extension Dictionary where Key: CustomDebugStringConvertible, Value:CustomDebugStringConvertible {

    func prettyPrint(){
        for (key,value) in self {
            print("\(key) = \(value)")
        }
    }
}

Применение:

dictionary.prettyprint //var prettyprint
dictionary.prettyPrint //func prettyPrint

Вывод (протестирован на игровой площадке Xcode 8 beta 2):

A = alfa
B = bravo
C = charlie
D = delta
E = echo
F = foxtrot
Асдрубал
источник
1
Есть ли причина, по которой вы сделали prettyprint var, а не просто функцию?
Хайден Холлиган,
Честно говоря, не думаю, что это имеет значение (могу ошибаться). Но если вы используете его много, то набирать меньше. Но поднимите интересный вопрос.
Asdrubal
3
Поскольку уже есть descriptionи debugDescription, может быть более подходящим вызвать var prettyDescriptionи вернуть отформатированную строку.
Толанд Хон
5

Методология преобразования словаря Swift в json и обратно самая изящная. Я использую долото Facebook, в котором есть команда pjson для печати словаря Swift. Например:

(lldb) pjson dict as NSDictionary

Это должно красиво напечатать словарь. Это гораздо более чистый способ сделать то, что уже было предложено. PS На данный момент вам придется использовать dict как NSDictionary, потому что среда выполнения Objective-C не понимает словари Swift. Я уже поднял пиар на зубило, чтобы избавиться от этого ограничения.

ОБНОВЛЕНИЕ: мой PR принят. Теперь вы можете использовать команду psjson вместо упомянутой выше команды pjson .

Jarora
источник
4

Для Swift 3 (и основываясь на блестящем ответе @Jalakoo ) сделайте следующее Dictionaryрасширение:

extension Dictionary where Key: ExpressibleByStringLiteral, Value: Any {
    var prettyPrint: String {
        return String(describing: self as AnyObject)
    }
}

затем распечатайте словарь любой иерархии в красивом способом (лучше dump()) с помощью этого:

print(dictionary!.prettyPrint)
Абдель Хади
источник
4

Детали

  • Xcode 10.2.1 (10E1001), Swift 5

Решение

extension Dictionary {
    func format(options: JSONSerialization.WritingOptions) -> Any? {
        do {
            let jsonData = try JSONSerialization.data(withJSONObject: self, options: options)
            return try JSONSerialization.jsonObject(with: jsonData, options: [.allowFragments])
        } catch {
            print(error.localizedDescription)
            return nil
        }
    }
}

Применение

let dictionary: [String : Any] = [
                                    "id": 0,
                                    "bool": true,
                                    "int_array": [1,3,5],
                                    "dict_array": [
                                        ["id": 1, "text": "text1"],
                                        ["id": 1, "text": "text2"]
                                    ]
                                 ]
print("Regualr print:\n\(dictionary)\n")
guard let formatedDictionary = dictionary.format(options: [.prettyPrinted, .sortedKeys]) else { return }
print("Pretty printed:\n\(formatedDictionary)\n")

Полученные результаты

введите описание изображения здесь

Василий Боднарчук
источник
2

Скорректировано на основе моего другого ответа здесь .

Решение PrettyPrint JSON с использованием псевдонима LLDB

Код не нужен

  • Чтобы получить хорошее форматирование json (отступы, новые строки и т. Д.), Вы можете определить псевдоним lldb, выполнив эту команду в своем терминале lldb ( источник ):
command regex pjson 's/(.+)/expr print(NSString(string: String(data: try! JSONSerialization.data(withJSONObject: %1, options: .prettyPrinted), encoding: .utf8)!))/'
  • Вероятно, вы не захотите заново определять псевдоним каждый раз, когда открываете XCode, поэтому выполните следующую команду, чтобы добавить определение псевдонима к ~/.lldbinit:
echo "command regex pjson 's/(.+)/expr print(NSString(string: String(data: try! JSONSerialization.data(withJSONObject: %1, options: .prettyPrinted), encoding: .utf8)!))/'" >> ~/.lldbinit
  • Это создаст pjsonпсевдоним, который вы можете использовать в своем терминале lldb в XCode:
pjson object

Сравнение результатов для следующего объекта Swift:

// Using Any? to demo optional & arbitrary Type
let dictionary: Any? = [
    "embedded": [
        "JustForTheSakeOfTheDemo": 42
    ],
    "A" : "alfa",
    "B" : "bravo",
    "C" : "charlie",
    "D" : "delta",
    "E" : "echo",
    "F" : "foxtrot"
]

✅ Вывод pjson dictionary

{
  "F" : "foxtrot",
  "D" : "delta",
  "embedded" : {
    "JustForTheSakeOfTheDemo" : 42
  },
  "E" : "echo",
  "A" : "alfa",
  "C" : "charlie",
  "B" : "bravo"
}

❌ Выход p dictionary

(Any?) $R0 = 7 key/value pairs {
  [0] = {
    key = "F"
    value = "foxtrot"
  }
  [1] = {
    key = "D"
    value = "delta"
  }
  [2] = {
    key = "embedded"
    value = 1 key/value pair {
      [0] = (key = "JustForTheSakeOfTheDemo", value = 42)
    }
  }
  [3] = {
    key = "E"
    value = "echo"
  }
  [4] = {
    key = "A"
    value = "alfa"
  }
  [5] = {
    key = "C"
    value = "charlie"
  }
  [6] = {
    key = "B"
    value = "bravo"
  }
}

❌ Выход p (dictionary as! NSDictionary)

(NSDictionary) $R18 = 0x0000000281e89710 {
  ObjectiveC.NSObject = {
    base__SwiftNativeNSDictionaryBase@0 = {
      baseNSDictionary@0 = {
        NSObject = {
          isa = Swift._SwiftDeferredNSDictionary<Swift.String, Any> with unmangled suffix "$"
        }
      }
    }
  }
}

❌ Выход po dictionary

Optional<Any>
  ▿ some : 7 elements
    ▿ 0 : 2 elements
      - key : "F"
      - value : "foxtrot"1 : 2 elements
      - key : "D"
      - value : "delta"2 : 2 elements
      - key : "embedded"
      ▿ value : 1 element
        ▿ 0 : 2 elements
          - key : "JustForTheSakeOfTheDemo"
          - value : 423 : 2 elements
      - key : "E"
      - value : "echo"4 : 2 elements
      - key : "A"
      - value : "alfa"5 : 2 elements
      - key : "C"
      - value : "charlie"6 : 2 elements
      - key : "B"
      - value : "bravo"

❌ Выход po print(dictionary)

Optional(["F": "foxtrot", "D": "delta", "embedded": ["JustForTheSakeOfTheDemo": 42], "E": "echo", "A": "alfa", "C": "charlie", "B": "bravo"])
Agirault
источник
1

swift 5, xcode 10.3:

po print(<your Plist container>)
По украине
источник
1

При отладке выведите структуру, которая соответствует протоколу Codable, на консоль с
использованием формата json.

extension Encodable {
    var jsonData: Data? {
        let encoder = JSONEncoder()
        encoder.outputFormatting = .prettyPrinted
        return try? encoder.encode(self)
    }
}

extension Encodable where Self: CustomDebugStringConvertible {
    var debugDescription: String {
         if let data = self.jsonData,
             let string = String(data: data, encoding: .utf8) {
             return string
         }
         return "can not convert to json string"
     }
}

strcut соответствует CustomDebugStringConvertible

struct Test: Codable, CustomDebugStringConvertible {
    let a: String
    let b: Int
}

let t = Test(a: "test string", b: 30)

структура печати отладки

(lldb) p print(t)
{
  "a" : "test string",
  "b" : 30
}
wlixcc
источник
1

Довольно печать из объекта данных:

let jsonObj = try JSONSerialization.jsonObject(with: data, options: [])
            let jsonData = try JSONSerialization.data(withJSONObject: jsonObj, options: [.prettyPrinted])
            print(String(data: jsonData, encoding: .utf8)!)
Уго Жордао
источник
1
Это круто! Вы можете использовать этот код с псевдонимом lldb, чтобы легко вычислить json в терминале отладки (подробности здесь ).
Agirault
0

Как насчет:

import Foundation

extension Dictionary {
    var myDesc: String {
        get {
            var v = ""
            for (key, value) in self {
                v += ("\(key) = \(value)\n")
            }
            return v
        }
    }
}


// Then, later, for any dictionary:
print(dictionary.myDesc)
BaseZen
источник
0
extension String {

    var conslePrintString: String {

        guard let data = "\""
            .appending(
                replacingOccurrences(of: "\\u", with: "\\U")
                    .replacingOccurrences(of: "\"", with: "\\\"")
            )
            .appending("\"")
            .data(using: .utf8) else {

            return self
        }

        guard let propertyList = try? PropertyListSerialization.propertyList(from: data,
                                                                             options: [],
                                                                             format: nil) else {
            return self
        }

        guard let string = propertyList as? String else {
            return self
        }

        return string.replacingOccurrences(of: "\\r\\n", with: "\n")
    }
}

let code in extension String and it works fine 

let string = "\(jsonDictionary)".conslePrintString
хасаякей
источник