0

I am using Swift 5 for a server side development (Kitura) and since the template engine doesn't have a way to trim long text (think the body of a blog post) I was wondering how to trim it in Swift directly. Other questions address it differently (just a string not from a loop) so here is my code:

router.get("/admin", handler: {
 request , response,next  in

    let documents = try collection.find()
    var pages: [[String: String]] = []

    for d in documents {
        print(d)
        pages.append(["title": d.title, "slug": d.slug, "body": d.body, "date": d.date])


 // I would like to trim the value of d.body

        print(d)
    }
    // check if an error occurred while iterating the cursor
    if let error = documents.error {
        throw error
    }
    try response.render("mongopages.stencil", with: ["Pages": pages])
    response.status(.OK)
})

return router
}()

how to trim the value of d.body to trim it to the first 50 characters?

devnull
  • 2,752
  • 1
  • 21
  • 38
  • You might need to be a bit more precise about what you mean by 'trim'. Limit to a specific length? Cut at word boundaries? Limit to a number of words? Do you want to add in anything to show it's been trimmed? etc etc. – flanker Dec 07 '20 at 20:46
  • @flanker my bad: I mean limit to say 10 words or 50 characters. Add "..." after the trimming :) – devnull Dec 07 '20 at 20:47

1 Answers1

3

You can extend String to give you this functionality (or extract it).

extension String {
    func truncate(to limit: Int, ellipsis: Bool = true) -> String {
        if count > limit {
            let truncated = String(prefix(limit)).trimmingCharacters(in: .whitespacesAndNewlines)
            return ellipsis ? truncated + "\u{2026}" : truncated
        } else {
            return self
        }
    }
}

let default = "Coming up with this sentence was the hardest part of this.".truncate(to: 50)
print(default) // Coming up with this sentence was the hardest part…

let modified = "Coming up with this sentence was the hardest part of this.".truncate(to: 50, ellipsis: false)
print(modified) // Coming up with this sentence was the hardest part

And in your use case:

router.get("/admin", handler: { (request, response, next)  in
    let documents = try collection.find()
    var pages: [[String: String]] = []
    
    for d in documents {
        let truncatedBody = d.body.truncate(to: 50)
        pages.append(["title": d.title, "slug": d.slug, "body": truncatedBody, "date": d.date])
    }
    
    ...
})
trndjc
  • 11,654
  • 3
  • 38
  • 51
  • 1
    This would cut any word in the middle so it could endup like th… – Leo Dabus Dec 07 '20 at 21:33
  • @LeoDabus I actually prefer it this way but I can see how others may not. Is there anything in Swift to easily implement this or would the OP have to find the first space before the limit manually? – trndjc Dec 07 '20 at 21:41
  • this is very interesting. So Swift has no default way to slice or truncate a string without extending String ? – devnull Dec 07 '20 at 22:08
  • @devnull there is in UIKit UILabel not string https://developer.apple.com/documentation/uikit/uilabel/1620525-linebreakmode [linebreakmode](https://developer.apple.com/documentation/uikit/nslinebreakmode) – Leo Dabus Dec 07 '20 at 22:10
  • @devnull you don’t need to use an extension (but it’s convenient) and Swift does have native string slicing (I used it in my extension) but for a custom implementation like this one there is nothing on the shelf currently. – trndjc Dec 07 '20 at 22:11