Быстро удалить все нечисловые символы из строки

84

Мне нужно проанализировать некоторые неизвестные данные, которые должны быть просто числовыми, но могут содержать пробелы или другие не буквенно-цифровые символы.

Есть ли новый способ сделать это в Swift? Все, что я могу найти в Интернете, похоже, это старый способ работы на C.

Я смотрю stringByTrimmingCharactersInSet- поскольку я уверен, что мои входные данные будут иметь только пробелы / специальные символы в начале или в конце строки. Могу ли я использовать для этого какие-либо встроенные наборы символов? Или мне нужно создать свою?

Я надеялся, что будет что-то вроде того, stringFromCharactersInSet()что позволит мне указать только допустимые символы для сохранения

Дэн
источник

Ответы:

183

Я надеялся, что будет что-то вроде stringFromCharactersInSet (), которое позволит мне указать только допустимые символы для сохранения.

Вы можете использовать trimmingCharactersс invertedнабором символов для удаления символов из начала или конца строки. В Swift 3 и новее:

let result = string.trimmingCharacters(in: CharacterSet(charactersIn: "0123456789.").inverted)

Или, если вы хотите удалить не-цифровые символы в любом месте в строке ( а не только в начале или в конце), вы можете , например , в Swift 4.2.1:filtercharacters

let result = string.filter("0123456789.".contains)

Или, если вы хотите удалить символы из CharacterSet из любого места в строке, используйте:

let result = String(string.unicodeScalars.filter(CharacterSet.whitespaces.inverted.contains))

Или, если вы хотите сопоставить только допустимые строки определенного формата (например, ####.##), вы можете использовать регулярное выражение. Например:

if let range = string.range(of: #"\d+(\.\d*)?"#, options: .regularExpression) {
    let result = string[range] // or `String(string[range])` if you need `String`
}

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


Для более старого синтаксиса Swift 2 см. Предыдущую версию этого ответа .

Роб
источник
Можете ли вы объяснить, почему вам нужно делать invertedэто с набором символов в примере Swift 3?
Энди Ибанез
4
@AndyIbanez Это все равно что сказать: если "ABC" - символы, которые я хочу сохранить, то обрезайте все, что не "ABC".
Скотт Маккензи
1
В Swift 4.2.1 let result = String(string.characters.filter { "01234567890.".characters.contains($0) })можно сократить доlet result = string.filter("01234567890.".contains)
Leo
41
let result = string.stringByReplacingOccurrencesOfString("[^0-9]", withString: "", options: NSStringCompareOptions.RegularExpressionSearch, range:nil).stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet())

Swift 3

let result = string.replacingOccurrences( of:"[^0-9]", with: "", options: .regularExpression)

Вы можете проголосовать за этот ответ .

Том Ховард
источник
3
Благодаря! после получения всех изменений Swift3 у меня осталось следующее: myStr.replacingOccurrences (of: "[^ 0-9]", с: "", options: .regularExpression)
bobwki
29

Я предпочитаю это решение , потому что мне нравятся расширения, и мне оно кажется немного чище. Решение воспроизведено здесь:

extension String {
    var digits: String {
        return components(separatedBy: CharacterSet.decimalDigits.inverted)
            .joined()
    }
}
Джейк Кронин
источник
Кажется, что
лишены
18

Swift 4

Я нашел достойный способ получить из строки только буквенно-цифровые символы . Например:-

func getAlphaNumericValue() {

    var yourString  = "123456789!@#$%^&*()AnyThingYouWant"

    let unsafeChars = CharacterSet.alphanumerics.inverted  // Remove the .inverted to get the opposite result.  

    let cleanChars  = yourString.components(separatedBy: unsafeChars).joined(separator: "")


    print(cleanChars)  // 123456789AnyThingYouWant

}
Аашиш
источник
17

Вы можете отфильтровать UnicodeScalarView строки с помощью оператора сопоставления с образцом для диапазонов, передать UnicodeScalar ClosedRange от 0 до 9 и инициализировать новую строку с полученным UnicodeScalarView:

extension String {
    private static var digits = UnicodeScalar("0")..."9"
    var digits: String {
        return String(unicodeScalars.filter(String.digits.contains))
    }
}

"abc12345".digits   // "12345"

изменить / обновить:

Swift 4.2

extension RangeReplaceableCollection where Self: StringProtocol {
    var digits: Self {
        return filter(("0"..."9").contains)
    }
}

или как метод мутации

extension RangeReplaceableCollection where Self: StringProtocol {
    mutating func removeAllNonNumeric() {
        removeAll { !("0"..."9" ~= $0) }
    }
}

Swift 5.2 • Xcode 11.4 или новее

В Swift5 мы можем использовать новое свойство Character, которое называется isWholeNumber:

extension RangeReplaceableCollection where Self: StringProtocol {
    var digits: Self { filter(\.isWholeNumber) }
}

extension RangeReplaceableCollection where Self: StringProtocol {
    mutating func removeAllNonNumeric() {
        removeAll { !$0.isWholeNumber }
    }
}

Чтобы разрешить период, мы можем расширить Character и создать вычисляемое свойство:

extension Character {
    var isDecimalOrPeriod: Bool { "0"..."9" ~= self || self == "." }
}

extension RangeReplaceableCollection where Self: StringProtocol {
    var digitsAndPeriods: Self { filter(\.isDecimalOrPeriod) }
}

Тестирование детской площадки:

"abc12345".digits   // "12345"

var str = "123abc0"
str.removeAllNonNumeric()
print(str) //"1230"

"Testing0123456789.".digitsAndPeriods // "0123456789."
Лео Дабус
источник
Отличное решение для Swift 5! Как я могу уйти ». или "," внутри String, чтобы иметь возможность преобразовать String в Double?
Ханс Бондока
1
@HansBondoka Спасибо. Попробуй вот так filter { $0.isNumber || $0 == "." }.
Лео Дабус
11

Решение с использованием filterфункции иrangeOfCharacterFromSet

let string = "sld [f]34é7*˜µ"

let alphaNumericCharacterSet = NSCharacterSet.alphanumericCharacterSet()
let filteredCharacters = string.characters.filter {
  return  String($0).rangeOfCharacterFromSet(alphaNumericCharacterSet) != nil
}
let filteredString = String(filteredCharacters) // -> sldf34é7µ

Чтобы отфильтровать только числовые символы, используйте

let string = "sld [f]34é7*˜µ"

let numericSet = "0123456789"
let filteredCharacters = string.characters.filter {
  return numericSet.containsString(String($0))
}
let filteredString = String(filteredCharacters) // -> 347

или же

let numericSet : [Character] = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
let filteredCharacters = string.characters.filter {
  return numericSet.contains($0)
}
let filteredString = String(filteredCharacters) // -> 347
вадиан
источник
Я не хочу никаких альфа-значений, хотя и не ожидаю их
Дэн
Пожалуйста, будьте более конкретными. В заголовке написано non-alphanumeric;-) Я редактировал ответ для числовых символов.
vadian
8

Swift 4

Но без расширений или компонентовSeparatedByCharactersInSet, которые также не читаются.

let allowedCharSet = NSCharacterSet.letters.union(.whitespaces)
let filteredText = String(sourceText.unicodeScalars.filter(allowedCharSet.contains))
Стив Мозер
источник
4

Swift 3, фильтрует все, кроме чисел

let myString = "dasdf3453453fsdf23455sf.2234"
let result = String(myString.characters.filter { String($0).rangeOfCharacter(from: CharacterSet(charactersIn: "0123456789")) != nil })
print(result)
CodeOverRide
источник
3

Swift 4.2

let numericString = string.filter { (char) -> Bool in
    return char.isNumber
}
mef27
источник
2

Вы можете сделать что-то вроде этого ...

let string = "[,myString1. \"" // string : [,myString1. " 
let characterSet = NSCharacterSet(charactersInString: "[,. \"")
let finalString = (string.componentsSeparatedByCharactersInSet(characterSet) as NSArray).componentsJoinedByString("") 
print(finalString)   
//finalString will be "myString1"
Вивек Такрани
источник
У меня нет полного представления о том, какие символы могут быть в строке, и мне нужны только числовые значения в конце. Это потребует от меня перечислить всех персонажей, которых я не хочу ... есть много персонажей, которые могут быть
Дэн
2

Проблема с первым решением Роба заключается в stringByTrimmingCharactersInSetфильтрации только концов строки, а не всей строки, как указано в документации Apple:

Возвращает новую строку, полученную путем удаления с обоих концов символов-получателей, содержащихся в данном наборе символов.

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

"$$1234%^56()78*9££".componentsSeparatedByCharactersInSet(NSCharacterSet(charactersInString: "0123456789").invertedSet)).joinWithSeparator("")

Что возвращается 123456789

Райан Броди
источник
Не нужно использовать NSCharacterSet. Но ваш ответ лучший. Вот общая версия:extension String { func removingCharactersNot(in charSet: CharacterSet) -> String { return self.components(separatedBy: charSet.inverted).joined(separator: "") } }
xaphod
2

Swift 3

extension String {
    var keepNumericsOnly: String {
        return self.components(separatedBy: CharacterSet(charactersIn: "0123456789").inverted).joined(separator: "")
    }
}
Эхаб Сайфан
источник
2
let string = "+1*(234) fds567@-8/90-"
let onlyNumbers = string.components(separatedBy: CharacterSet.decimalDigits.inverted).joined()

print(onlyNumbers) // "1234567890"

или же

extension String {

  func removeNonNumeric() -> String {
    return self.components(separatedBy: CharacterSet.decimalDigits.inverted).joined()
  }
}

let onlyNumbers = "+1*(234) fds567@-8/90-".removeNonNumeric() 
print(onlyNumbers)// "1234567890"
Владимир Пчеляков
источник
1

Версия Swift 4.0

extension String {
    var numbers: String {
        return String(describing: filter { String($0).rangeOfCharacter(from: CharacterSet(charactersIn: "0123456789")) != nil })
    }
}
Rockdaswift
источник
1

Swift 4

String.swift

import Foundation

extension String {

    func removeCharacters(from forbiddenChars: CharacterSet) -> String {
        let passed = self.unicodeScalars.filter { !forbiddenChars.contains($0) }
        return String(String.UnicodeScalarView(passed))
    }

    func removeCharacters(from: String) -> String {
        return removeCharacters(from: CharacterSet(charactersIn: from))
    }
}

ViewController.swift

let character = "1Vi234s56a78l9"
        let alphaNumericSet = character.removeCharacters(from: CharacterSet.decimalDigits.inverted)
        print(alphaNumericSet) // will print: 123456789

        let alphaNumericCharacterSet = character.removeCharacters(from: "0123456789")
        print("no digits",alphaNumericCharacterSet) // will print: Vishal
Вишал Вагасия
источник
Инициализировать новый UnicodeScalarView бессмысленно. Результатом фильтра это уже UnicodeScalarView. return String(passed)
Лео Дабус
1

Swift 4.2

let digitChars  = yourString.components(separatedBy:
        CharacterSet.decimalDigits.inverted).joined(separator: "")
Дебаприо Б
источник
0

Версия Swift 3

extension String
{
    func trimmingCharactersNot(in charSet: CharacterSet) -> String
    {
        var s:String = ""
        for unicodeScalar in self.unicodeScalars
        {
            if charSet.contains(unicodeScalar)
            {
                s.append(String(unicodeScalar))
            }
        }
        return s
    }
}
хамм
источник