0

I am looking to run a quick function in Swift to change certain aspects of a string.

Objective: Take input string [UITextField] and replace all punctuation followed by a space (. ) or (? ) with just the punctuation be itself within the string

Problem: I do not know what the punctuation will be. There is a UITextField for the user to enter this in. This textfield is used for other functions as well.

Example: Input: Hello, how are you doing? I am doing fine. Thank you. Output: Hello,how are you doing?I am doing fine.Thank you.

Test Code: I also have a Swift Stub (JSFiddle for Swift) if you want to test in browser.

var inputText = "hello, how are you doing? I am okay. Thanks." // User input from UITextField

var newString: String! // Setting string for global variable

var punctuation: String = "" // Starts as blank, could remain empty
punctuation = "?.," // Dont know what this will be. Input from UITextField

var characters = Array(punctuation)
println(characters) //Testing in console 

//Current idea but does not work as needed
func replacePunctuationSpace() -> String{

    for character in characters{
        newString = inputText.stringByReplacingOccurrencesOfString("\(character) ", withString: "\(character)")
        println("Replacing \(character)  ... \(newString)")   
    }
    return newString

}
replacePunctuationSpace()

//Only replaces last item in array
println(newString)

Please let me know if something doesn't make sense.

Thanks for the help. Eric

3 Answers 3

3

You should be able to use an NSRegularExpression and a method like replaceMatchesInString:options:range:withTemplate:.

I am no expert on regular expressions. I believe that you can make your regular expression have 2 "capture groups" where the first capture group is a list of possible punctuation characters, and the second is a variable amount of whitespace. Your template would tell the `replaceMatchesInString:options:range:withTemplate: function to replace each matched expression with the just the contents of the first capture group (the matched punctuation symbol.)

You will need to list all the punctuation symbols that you want to handle (e.g. ".,:?!;")

Edit:

I decided to use this as a learning experience to learn more about regular expressions.

I found this page that is a decent introduction to regular expressions.

Then I read the docs on NSRegularExpression, and in particular, the stringByReplacingMatchesInString function. That says that the string is replaced based on a "template".

It seems that the parts of a regular expression can be divided into "capture groups", or sections that get matched separately. You can then use those capture groups to use parts of the matched string to the output of stringByReplacingMatchesInString.

Here is some playground code I wrote that searches for the punctuation characters ",.:;?!" followed by one or more whitespace characters and replaces them with just the punctuation, stripping away the whitespace:

var error: NSError?
let myRegEx = NSRegularExpression(pattern: "([,.:;?!])(\\s*)",
  options: NSRegularExpressionOptions(0),
  error: &error)

let testString = "This is a string, with some text.   It has punctuation; can we replace that punctuation? I need to know what happens! "
let range = NSRange(location: 0, length: count(testString))
println(testString)
if let newString = myRegEx?.stringByReplacingMatchesInString(
  testString,
  options: NSMatchingOptions(0),
  range: range,
  withTemplate: "$1")
{
  println("Result string = \(newString)")
}
else
{
  println("No matches")
}

Apparently you create capture groups by enclosing part of your regular expression in parentheses. So I defined a regular expression with 2 capture groups. The first capture group is a "character class" that means any of the punctuation symbols: ,.:;?!. That part of the regular expression looks like this: ([,.:;?!]).

The second capture group matches any number of whitespace characters. The special "character class" for whitespace is \s. However, Swift strings also use a backslash for escaping, so in order to get a literal backslash in the regular expression, I had to write it as \\s. Putting that in parenthesis turns it into a capture group: (\\s).

In the call to stringByReplacingMatchesInString the regular expression is ([,.:;?!])(\\s*) and the template string is "$1".

That means:

Match strings that consist of a punctuation character followed by zero or more whitespace characters. Put the punctuation character of each match in "capture group" 1, and the whitespace in capture group 2".

Replace each match with the contents of capture group 1, which is the punctuation character.

That has the effect of discarding the whitespace from capture group 2, thus getting rid of whitespace after the specified punctuation characters.

Sign up to request clarification or add additional context in comments.

5 Comments

Here's a tutorial to learn using Regex: raywenderlich.com/30288/…
There is also a "punctuation character class": pattern: "(\\p{Punct})(\\s*)" :) See regular-expressions.info/posixbrackets.html.
Does Cocoa's RegEx engine support all those Unicode bracket expressions?
Trying it but getting. 'String is not convertible to 'NSRange'. Am i doing this wrong?
The code I posted works if you copy it and paste it into a playground. You must have made an editing error in putting it into your program
2

This can (for example) be achieved with NSScanner. The following code should be self-explaining :)

let inputText = "hello, how are you doing? I am okay. Thanks."
var outputText = ""

let punkt = NSCharacterSet.punctuationCharacterSet()
let space = NSCharacterSet.whitespaceCharacterSet()

let scanner = NSScanner(string: inputText)
while !scanner.atEnd {
    var tmp : NSString?
    if scanner.scanUpToCharactersFromSet(punkt, intoString: &tmp) {
        outputText += tmp as! String
        if scanner.scanCharactersFromSet(punkt, intoString: &tmp) {
            outputText += tmp as! String
            scanner.scanCharactersFromSet(space, intoString: nil)
        }
    }
}

println(outputText)
// hello,how are you doing?I am okay.Thanks.

4 Comments

Very nice! I search a bit but couldn't find this NSCharacterSet.punctuationCharacterSet() in documentation.
@pteofil: It is listed in the NSCharacterSet reference: developer.apple.com/library/mac/documentation/Cocoa/Reference/….
Thanks @Martin R :) I found it easily after seeing you use it. What I didn't know was that it's a method of NSCharacterSet. I tried searching for it on NSString...
Thank you very much. I am using the answer @Joe provided but yours does work great! I am unsure of which answer, yours or Joe's to mark as correct.
1

Disclaimer: I have never written Swift

The issue is that you are only ever modifying the inputText variable. Each iteration of your loop is starting over with the original input text.

Try something like this:

var inputText = "hello, how are you doing? I am okay. Thanks." // User input from UITextField

var newString: String! // Setting string for global variable

var punctuation: String = "" // Starts as blank, could remain empty
punctuation = "?.," // Dont know what this will be. Input from UITextField

var characters = Array(punctuation)
println(characters) //Testing in console 

//Current idea but does not work as needed
func replacePunctuationSpace() -> String {
    newString = inputText
    for character in characters{
        newString = newString.stringByReplacingOccurrencesOfString("\(character) ", withString: "\(character)")
        println("Replacing \(character)  ... \(newString)")   
    }
    return newString
}
replacePunctuationSpace()

//Only replaces last item in array
println(newString)

http://swiftstub.com/716967254/

1 Comment

Thanks so much. I appreciate that you used my existing code and explained what I was doing wrong. Also, that you stuck with swift. It also shows how easy swift is to pick up as you have not written it before.

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.