Прецизионный спецификатор формата строки в Swift

351

Ниже показано, как бы я раньше усекал поплавок до двух знаков после запятой

NSLog(@" %.02f %.02f %.02f", r, g, b);

Я проверил документы и электронную книгу, но не смог понять это. Спасибо!

Теги:

30 ответов

265
Лучший ответ

Мое лучшее решение до сих пор, следуя из ответа Дэвида:

import Foundation

extension Int {
    func format(f: String) -> String {
        return String(format: "%\(f)d", self)
    }
}

extension Double {
    func format(f: String) -> String {
        return String(format: "%\(f)f", self)
    }
}

let someInt = 4, someIntFormat = "03"
println("The integer number \(someInt) formatted with \"\(someIntFormat)\" looks like \(someInt.format(someIntFormat))")
// The integer number 4 formatted with "03" looks like 004

let someDouble = 3.14159265359, someDoubleFormat = ".3"
println("The floating point number \(someDouble) formatted with \"\(someDoubleFormat)\" looks like \(someDouble.format(someDoubleFormat))")
// The floating point number 3.14159265359 formatted with ".3" looks like 3.142

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

  • 56
    Это излишне сложно. Ответ от реалии работает и является гораздо более кратким.
  • 6
    Конечно, если вы используете его только один раз. Но если вы хотите иметь больше опций форматирования с использованием интерполяции строк (что намного удобнее для чтения), вы можете поместить все расширения форматирования в файл в другом месте и ссылаться на него в рамках всего проекта. Конечно, в идеале Apple должна предоставить библиотеку форматирования.
Показать ещё 2 комментария
676

простой способ:

print(String(format: "hex string: %X", 123456))
print(String(format: "a float number: %.5f", 1.0321))
  • 7
    println(String(format: "a float number: %.5f", 1.0321))
  • 67
    Я считаю, что это лучший ответ, чем принятый ответ. Это намного ближе к стандартному c-style printf без необходимости писать отдельные расширения.
Показать ещё 6 комментариев
116

Я нашел, что String.localizedStringWithFormat работает достаточно хорошо:

Пример:

let value: Float = 0.33333
let unit: String = "mph"

yourUILabel.text = String.localizedStringWithFormat("%.2f %@", value, unit)
  • 0
    Вопрос не имеет ничего общего с единицами обработки. localizedStringWithFormat - это хорошо, но не связано.
  • 0
    Я согласен, AmitP, это было задано до того, как String (формат: ..., аргументы: ...) был доступен
70

Это очень быстрый и простой способ, которому не требуется сложное решение.

let duration = String(format: "%.01f", 3.32323242)
// result = 3.3
  • 0
    Это не компилируется (с использованием 3.0.2 в песочнице IBM Swift): Col 16: 'init' has been renamed to 'init(describing:)'
  • 0
    @PeterDillinger вы передаете необязательное, а не развернутое значение.
Показать ещё 1 комментарий
57

Большинство ответов здесь действительны. Однако, если вы часто форматируете число, подумайте о расширении класса Float, чтобы добавить метод, который возвращает форматированную строку. См. Пример кода ниже. Эта цель достигает той же цели, используя число форматирования и расширение.

extension Float {
    func string(fractionDigits:Int) -> String {
        let formatter = NSNumberFormatter()
        formatter.minimumFractionDigits = fractionDigits
        formatter.maximumFractionDigits = fractionDigits
        return formatter.stringFromNumber(self) ?? "\(self)"
    }
}

let myVelocity:Float = 12.32982342034

println("The velocity is \(myVelocity.string(2))")
println("The velocity is \(myVelocity.string(1))")

Консоль показывает:

The velocity is 12.33
The velocity is 12.3

Обновление SWIFT 3.1

extension Float {
    func string(fractionDigits:Int) -> String {
        let formatter = NumberFormatter()
        formatter.minimumFractionDigits = fractionDigits
        formatter.maximumFractionDigits = fractionDigits
        return formatter.string(from: NSNumber(value: self)) ?? "\(self)"
    }
}
  • 9
    Я хотел бы, чтобы больше людей использовали NSNumberFormatter , как этот ответ. Другие ответы с высоким рейтингом просто не отражают настройки локали устройства (например, в некоторых локалях они используют запятую для десятичного разряда; это отражает это; другие ответы нет).
  • 3
    Единственное улучшение, которое я хотел бы видеть, - это сохранение средства форматирования для любого заданного числа - NSNumberFormatters создавать дорого.
Показать ещё 3 комментария
31

Вы не можете сделать это (пока) со строчной интерполяцией. Лучше всего по-прежнему будет форматирование NSString:

println(NSString(format:"%.2f", sqrt(2.0)))

Экстраполируя из python, кажется, что разумный синтаксис может быть:

@infix func % (value:Double, format:String) -> String {
    return NSString(format:format, value)
}

Что затем позволяет использовать их как:

M_PI % "%5.3f"                // "3.142"

Вы можете определить похожие операторы для всех числовых типов, к сожалению, я не нашел способ сделать это с помощью генериков.

  • 0
    где вы нашли этот синтаксис `NSString (format:" formatString ", val) '. Я не вижу этого в документе iBooks от Apple.
  • 1
    Это то же самое, что построить любой объект-объект из Swift. Это быстрая версия [NSString stringWithFormat...
Показать ещё 6 комментариев
12
import Foundation

extension CGFloat {
    var string1: String {
        return String(format: "%.1f", self)
    }
    var string2: String {
        return String(format: "%.2f", self)
    }
}

Использование

let offset = CGPoint(1.23, 4.56)
print("offset: \(offset.x.string1) x \(offset.y.string1)")
// offset: 1.2 x 4.6
  • 0
    лучший ответ.
11

Почему это так сложно? Вы можете использовать это вместо:

import UIKit

let PI = 3.14159265359

round( PI ) // 3.0 rounded to the nearest decimal
round( PI * 100 ) / 100 //3.14 rounded to the nearest hundredth
round( PI * 1000 ) / 1000 // 3.142 rounded to the nearest thousandth

Посмотрите, как это работает на Playground.

PS: Решение от: http://rrike.sh/xcode/rounding-various-decimal-places-swift/

  • 0
    Это, безусловно, лучшее решение, я не понимаю, как это не на вершине.
  • 5
    Нечеткая вещь .. 1.500000000 будет только "1,5", а не "1,50"
Показать ещё 1 комментарий
10

Более элегантным и универсальным решением является переписать оператор ruby ​​/python %:

// Updated for beta 5
func %(format:String, args:[CVarArgType]) -> String {
    return NSString(format:format, arguments:getVaList(args))
}

"Hello %@, This is pi : %.2f" % ["World", M_PI]
  • 0
    К сожалению, это умирает в бета-версии 6: фатальная ошибка: не может unsafeBitCast между типами разных размеров.
  • 0
    @binarymochi с бета-версией 6: "Hello %@, This is pi : %.2f" % ["World", M_PI] работает, но странно, что "%@ %@" % ["Hello", "World"] рейз can't unsafeBitCast ... Думаю, это будет исправлено в следующей версии.
Показать ещё 3 комментария
6

подробности

Xcode 9.3, Swift 4.1

Решение

import Foundation

extension Numeric {

    private func _precision(number: NSNumber, precision: Int, roundingMode: NumberFormatter.RoundingMode) -> Self? {
        let formatter = NumberFormatter()
        formatter.minimumFractionDigits = precision
        formatter.roundingMode = roundingMode
        if let formatedNumString = formatter.string(from: number), let formatedNum = formatter.number(from: formatedNumString) {
            return formatedNum as? Self
        }
        return nil

    }

    func precision(_ number: Int, roundingMode: NumberFormatter.RoundingMode = NumberFormatter.RoundingMode.halfUp) -> Self? {

        if let num = self as? NSNumber {
            return _precision(number: num, precision: number, roundingMode: roundingMode)
        }
        if let string = self as? String, let double = Double(string) {
            return _precision(number: NSNumber(value: double), precision: number, roundingMode: roundingMode)
        }
        return nil
    }

}

использование

import UIKit

func showInfo<T: Numeric>(value: T) {
    print("Type: \(type(of: value))")
    print("Original Value: \(value)")
    let value1 = value.precision(3)
    print("value1 = \(value1 != nil ? "\(value1!)" : "nil")")
    let value2 = value.precision(2)
    print("value2 = \(value2 != nil ? "\(value2!)" : "nil")")
    if let value1 = value1, let value2 = value2 {
        print("value1 + value2 = \(value1 + value2)")
    }
    print("")
}

let double: Double = 232.1987654321
let float = Float(double)
let cgfloat = CGFloat(double)

showInfo(value: double)
showInfo(value: float)
showInfo(value: cgfloat)

Результат

Изображение 1644

  • 0
    Это должен быть принятый ответ.
5

Swift 4

let string = String(format: "%.2f", locale: Locale.current, arguments: 15.123)
  • 0
    let temp: Float = div * 100 let string = String (формат: "% .2f", локаль: Locale.current, аргументы: temp). Это дает мне ошибку. Невозможно преобразовать значение типа 'Float' в ожидаемый тип аргумента '[CVarArg]
  • 0
    вам нужно поместить 15.123 в массив, чтобы он работал
Показать ещё 1 комментарий
5

Вы все еще можете использовать NSLog в Swift, как в Objective-C, без знака @.

NSLog("%.02f %.02f %.02f", r, g, b)

Изменить: После работы с Swift с течением времени я хотел бы добавить также эту вариацию

    var r=1.2
    var g=1.3
    var b=1.4
    NSLog("\(r) \(g) \(b)")

Вывод:

2014-12-07 21:00:42.128 MyApp[1626:60b] 1.2 1.3 1.4
4
extension Double {
  func formatWithDecimalPlaces(decimalPlaces: Int) -> Double {
     let formattedString = NSString(format: "%.\(decimalPlaces)f", self) as String
     return Double(formattedString)!
     }
 }

 1.3333.formatWithDecimalPlaces(2)
3

Ответы, полученные до сих пор, которые получили наибольшее количество голосов, полагаются на методы NSString и требуют, чтобы вы импортировали Foundation.

Сделав это, вы все еще имеете доступ к NSLog.

Итак, я думаю, что ответ на вопрос, если вы спрашиваете, как продолжать использовать NSLog в Swift, просто:

import Foundation

2
//It will more help, by specify how much decimal Point you want.
let decimalPoint = 2
let floatAmount = 1.10001
let amountValue = String(format: "%0.*f", decimalPoint, floatAmount)
2

меньше ввода текста:

func fprint(format: String, _ args: CVarArgType...) {
    print(NSString(format: format, arguments: getVaList(args)))
}
2

Сила расширения

extension Double {
    var asNumber:String {
        if self >= 0 {
            var formatter = NSNumberFormatter()
            formatter.numberStyle = .NoStyle
            formatter.percentSymbol = ""
            formatter.maximumFractionDigits = 1
            return "\(formatter.stringFromNumber(self)!)"
        }
        return ""
    }
}

let velocity:Float = 12.32982342034

println("The velocity is \(velocity.toNumber)")

Вывод: Скорость составляет 12,3

2

здесь "чистое" быстрое решение

 var d = 1.234567
operator infix ~> {}
@infix func ~> (left: Double, right: Int) -> String {
    if right == 0 {
        return "\(Int(left))"
    }
    var k = 1.0
    for i in 1..right+1 {
        k = 10.0 * k
    }
    let n = Double(Int(left*k)) / Double(k)
    return "\(n)"
}
println("\(d~>2)")
println("\(d~>1)")
println("\(d~>0)")
1

Множество хороших ответов выше, но иногда шаблон более подходит, чем "%.3f" вроде gobbledygook. Здесь я беру с помощью NumberFormatter в Swift 3.

extension Double {
  func format(_ pattern: String) -> String {
    let formatter = NumberFormatter()
    formatter.format = pattern
    return formatter.string(from: NSNumber(value: self))!
  }    
}

let n1 = 0.350, n2 = 0.355
print(n1.format("0.00#")) // 0.35
print(n2.format("0.00#")) // 0.355

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

1

Версия оператора Vincent Guerci ruby ​​/python%, обновленная для Swift 2.1:

func %(format:String, args:[CVarArgType]) -> String {
  return String(format:format, arguments:args)
}

"Hello %@, This is pi : %.2f" % ["World", M_PI]
1

используйте ниже метод

let output = String.localizedStringWithFormat(" %.02f %.02f %.02f", r, g, b)

println(output)
1

Также с округлением:

extension Float
{
    func format(f: String) -> String
    {
        return NSString(format: "%\(f)f", self)
    }
    mutating func roundTo(f: String)
    {
        self = NSString(format: "%\(f)f", self).floatValue
    }
}

extension Double
{
    func format(f: String) -> String
    {
        return NSString(format: "%\(f)f", self)
    }
    mutating func roundTo(f: String)
    {
        self = NSString(format: "%\(f)f", self).doubleValue
    }
}

x = 0.90695652173913
x.roundTo(".2")
println(x) //0.91
1

Вы также можете создать оператор таким образом

operator infix <- {}

func <- (format: String, args:[CVarArg]) -> String {
    return String(format: format, arguments: args)
}

let str = "%d %.1f" <- [1453, 1.123]
0

Как насчет расширений для типов Double и CGFloat:

extension Double {

   func formatted(_ decimalPlaces: Int?) -> String {
      let theDecimalPlaces : Int
      if decimalPlaces != nil {
         theDecimalPlaces = decimalPlaces!
      }
      else {
         theDecimalPlaces = 2
      }
      let theNumberFormatter = NumberFormatter()
      theNumberFormatter.formatterBehavior = .behavior10_4
      theNumberFormatter.minimumIntegerDigits = 1
      theNumberFormatter.minimumFractionDigits = 1
      theNumberFormatter.maximumFractionDigits = theDecimalPlaces
      theNumberFormatter.usesGroupingSeparator = true
      theNumberFormatter.groupingSeparator = " "
      theNumberFormatter.groupingSize = 3

      if let theResult = theNumberFormatter.string(from: NSNumber(value:self)) {
         return theResult
      }
      else {
         return "\(self)"
      }
   }
}

Использование:

let aNumber: Double = 112465848348508.458758344
Swift.print("The number: \(aNumber.formatted(2))")

отпечатано: 112 465 848 348 508,46

0

Обновление Swift 4 Xcode 10

extension Double {
    var asNumber:String {
        if self >= 0 {
            let formatter = NumberFormatter()
            formatter.numberStyle = .none
            formatter.percentSymbol = ""
            formatter.maximumFractionDigits = 2
            return "\(formatter.string(from: NSNumber(value: self)) ?? "")"
        }
        return ""
    }
}
0

Пример Swift2: Ширина экрана устройства iOS, форматирование Float, удаление десятичного числа

print(NSString(format: "Screen width = %.0f pixels", CGRectGetWidth(self.view.frame)))
0

@Христиан Дитрих:

вместо:

var k = 1.0
    for i in 1...right+1 {
        k = 10.0 * k
    }
let n = Double(Int(left*k)) / Double(k)
return "\(n)"

он также может быть:

let k = pow(10.0, Double(right))
let n = Double(Int(left*k)) / k
return "\(n)"

[Коррекция:] Извините за недоразумение * - Конечно, это работает с парными. Я думаю, что наиболее практично (если вы хотите, чтобы цифры округлялись, а не прерывались), это было бы примерно так:

infix operator ~> {}
func ~> (left: Double, right: Int) -> Double {
    if right <= 0 {
        return round(left)
    }
    let k = pow(10.0, Double(right))
    return round(left*k) / k
}

Только для Float просто замените Double Float, pow с powf и round roundf.
Обновление: Я обнаружил, что наиболее практичным является использование типа возврата Double вместо String. Он работает одинаково для вывода строки, т.е.:

println("Pi is roughly \(3.1415926 ~> 3)")

Отпечатки: Pi примерно 3.142
Таким образом, вы можете использовать его так же, как и для строк (вы даже можете писать: println (d ~ > 2)), но дополнительно вы также можете использовать его для округления значений напрямую, т.е.:

d = Double(slider.value) ~> 2

или что вам нужно...

  • 0
    Это, очевидно, предназначено для комментария, я понимаю, что вам нужно больше места, чтобы подчеркнуть, и это ценно, но если вы собираетесь написать его как полноценный ответ, сделайте его полезным самостоятельно, независимо; Вы можете добавить полный код, например, а затем сделать замечание и подтвердить для Кристиана.
  • 0
    @ Хайме Гомес: Мне не разрешено комментировать приведенный выше ответ. Но в любом случае, у меня была какая-то ложная интерпретация *. Не знаю, стоит ли его хранить или нужно удалить. Конечно, это может быть использовано аналогичным образом только для округления (без преобразования строк) и может быть легко переведено на другие языки программирования. * Я предположил, что с Double он округляется до 8 цифр, что, конечно, было ошибкой, потому что я сделал округление с Float и преобразовал его в Double случайно.
Показать ещё 2 комментария
0

Я не знаю о двух знаках после запятой, но здесь, как вы можете печатать поплавки с нулевыми знаками после запятой, поэтому я бы предположил, что это может быть 2 место, 3, места... (Примечание: вы должны преобразовать CGFloat в Двойной переход к String (формат:) или он увидит значение нуля)

func logRect(r: CGRect, _ title: String = "") {
    println(String(format: "[ (%.0f, %.0f), (%.0f, %.0f) ] %@",
        Double(r.origin.x), Double(r.origin.y), Double(r.size.width), Double(r.size.height), title))
}
0
@infix func ^(left:Double, right: Int) -> NSNumber {
    let nf = NSNumberFormatter()
    nf.maximumSignificantDigits = Int(right)
    return  nf.numberFromString(nf.stringFromNumber(left))
}


let r = 0.52264
let g = 0.22643
let b = 0.94837

println("this is a color: \(r^3) \(g^3) \(b^3)")

// this is a color: 0.523 0.226 0.948
-2

использование

CGFloat 

или же

Float.roundTo(places:2)
  • 1
    CGFloat не имеет участника в раунд

Ещё вопросы

Сообщество Overcoder
Наверх
Меню