2

Hello my Friends i need ur help! :) Im an absolute beginner in swift and have absolutely no idea what i'm doing.

I need to extract all numbers from a txt file which i converted into a string. I want to save all the numbers into a new Array and i also have to use CharacterView to solve the problem.

This is what i got so far. Reading from the txt file is no problem.

func readFile(){
    let path = Bundle.main.path(forResource: "paragraph", ofType: "txt")

    var fileContents : String? = nil
    do {
        fileContents = try String(contentsOfFile: path!, encoding: String.Encoding.utf8)
    } catch _ as NSError {
        //ERROR HANDLING
    }
     print(fileContents)

}

this is the file:

§ 9 Lorem ipsum dolor (1) sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam. (2) Bed diam voluptua. At vero eos et accusam et justo duo 55 dolores et ea rebum. Stet clita kasd gubergren. (3) 1 abore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd.

Thank you for your time!

8
  • What is the structure of your file? How do you plan on storing the numbers? Commented Jul 26, 2017 at 13:36
  • Include a sample of the content in your paragraph9.txt file Commented Jul 26, 2017 at 13:37
  • Thx for you answers. i added the txt file below the question Commented Jul 26, 2017 at 13:44
  • Show what output you are hoping to get. Do you just want [1,2,3]???? Or [9,1,2,55,3,1]??? What? Commented Jul 26, 2017 at 13:54
  • yeah exactly [9,1,2,55,3,1] Commented Jul 26, 2017 at 13:55

2 Answers 2

5

Details

  • Xcode 10.2.1 (10E1001), Swift 5

Solution

import Foundation

extension String {
    func onlyNumbers() -> [NSNumber] {
        let formatter = NumberFormatter()
        formatter.numberStyle = .decimal
        let charset = CharacterSet.init(charactersIn: " ,")
        return matches(for: "[+-]?([0-9]+([., ][0-9]*)*|[.][0-9]+)").compactMap { string in
            return formatter.number(from: string.trimmingCharacters(in: charset))
        }
    }

    // https://stackoverflow.com/a/54900097/4488252
    func matches(for regex: String) -> [String] {
        guard let regex = try? NSRegularExpression(pattern: regex, options: [.caseInsensitive]) else { return [] }
        let matches  = regex.matches(in: self, options: [], range: NSMakeRange(0, self.count))
        return matches.compactMap { match in
            guard let range = Range(match.range, in: self) else { return nil }
            return String(self[range])
        }
    }
}

Usage

let text = "dasdxcw 12345678 eadwd 333.222 reqw 3 333 444.22, sfsa 44. qewqwdsaw qe aw, 0.123456678 and .23 asdasdas 32,322,222,444.8"
print("Original text: \(text)")
print("Only numbers: \(text.onlyNumbers())")

Results

//Original text: dasdxcw 12345678 eadwd 333.222 reqw 3 333 444.22, sfsa 44. qewqwdsaw qe aw, 0.123456678 and .23 asdasdas 32,322,222,444.8
//Only numbers: [12345678, 333.222, 3333444.22, 44, 0.123456678, 0.23, 32322222444.8]
Sign up to request clarification or add additional context in comments.

Comments

2

Here's an easy way to do it, unfortunately it does not use CharacterView because that would complicate it greatly:

func readFile(){
  // Make sure getting the path and reading the file succeeds
  guard
    let path = Bundle.main.path(forResource: "paragraph", ofType: "txt"),
    let fileContents = try? String(contentsOfFile: path, encoding: String.Encoding.utf8) 
    else { return }

  // split string into substrings that only contain numbers
  let substrings = fileContents.components(separatedBy: CharacterSet.decimalDigits.inverted)

  // flatMap performs action on each substring
  // and only returns non-nil values,
  // thus returns [Int]

  let numbers = substrings.flatMap {
    // convert each substring into an Int?
    return Int($0)
  }

  print(numbers)
}

Because the initializer for Int takes a String there is no need to use CharacterView. Once the numbers in the text are split from their non-digits they can be converted directly from String to Int. To use CharacterView would be an unnecessary intermediate. You could, however, code your own version of Int init?(String) which uses CharacterView to build the value.

1 Comment

Note that I didn't need the variable substrings, I could have skipped it and done fileContents.components(separatedBy: CharacterSet.decimalDigits.inverted).flatMap { return Int($0) }. I separated it to demonstrate the steps involved.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.