0

My first question here. I have a code which is single line string which has a lot of symbols. String consists of many similar segments including date. I would like to search for a parts of string with date formatter of dd/mm/yy and insert new line \n symbol before date formatter. I think of using regex, however I am new to swift/proggraming. Can You advice me how to do it? thank you very much!

//Input string
Let configstring = "01/01/19 AAA BBB CCC DDD EEE FFF GGG HHH III JJJ KKK 0000 1111 0000 0000 1111 0000 0000 LLLL 01/02/19 MMM NNN OOO PPP RRR SSS TTT UUU 0000 1111 1111 0000 1111 1111 0000 1111 0000 0000 WWWW "

expected result string

Let configstring = "/n01/01/19 AAA BBB CCC DDD EEE FFF GGG HHH III JJJ KKK 0000 1111 0000 0000 1111 0000 0000 LLLL /n01/02/19 MMM NNN OOO PPP RRR SSS TTT UUU 0000 1111 1111 0000 1111 1111 0000 1111 0000 0000 WWWW "
KarolB
  • 21
  • 5

1 Answers1

1

You can use NSDataDetector to detect dates with any format in your string, get its NSRange, convert to Range<String.Index>, check if the string found on that range matches the desired date format and if it matches just insert the new line character at range.lowerBound:


extension Formatter {
    static let customDate: DateFormatter = {
        let dateFormatter = DateFormatter()
        dateFormatter.locale = Locale(identifier: "en_US_POSIX")
        dateFormatter.dateFormat = "dd/MM/yy"  // or "MM/dd/yy"
        return dateFormatter
    }()
}

Playground testing:

var configstring = "01/01/19 AAA BBB CCC DDD EEE FFF GGG HHH III JJJ KKK 0000 1111 0000 0000 1111 0000 0000 LLLL 01/02/19 MMM NNN OOO PPP RRR SSS TTT UUU 0000 1111 1111 0000 1111 1111 0000 1111 0000 0000 WWWW "

do {
    let ranges = try NSDataDetector(types: NSTextCheckingResult.CheckingType.date.rawValue)
            .matches(in: configstring, range: .init(configstring.startIndex..., in: configstring))
            .compactMap { Range<String.Index>($0.range, in: configstring) }
    for range in ranges.reversed() {
        // check if the date found matches the desired format
        if let date = Formatter.customDate.date(from: String(configstring[range])) {
            print("date match:", date)
            configstring.insert("\n", at: range.lowerBound)
        }
    }
} catch { 
    print(error) 
}

print(configstring)  // "\n01/01/19 AAA BBB CCC DDD EEE FFF GGG HHH III JJJ KKK 0000 1111 0000 0000 1111 0000 0000 LLLL \n01/02/19 MMM NNN OOO PPP RRR SSS TTT UUU 0000 1111 1111 0000 1111 1111 0000 1111 0000 0000 WWWW \n"

Or using regular expression

let pattern = "\\d{2}/\\d{2}/\\d{2}"  // or "(\\d{2}/){2}\\d{2}" or "\\d{2}(/\\d{2}){2}"
var configstring = "01/01/19 AAA BBB CCC DDD EEE FFF GGG HHH III JJJ KKK 0000 1111 0000 0000 1111 0000 0000 LLLL 01/02/19 MMM NNN OOO PPP RRR SSS TTT UUU 0000 1111 1111 0000 1111 1111 0000 1111 0000 0000 WWWW "
var startIndex = configstring.startIndex
while let range = configstring[startIndex...].range(of: pattern, options: .regularExpression) {
    // check if the date found matches the desired format
    if let date = Formatter.customDate.date(from: String(configstring[range])) {
        print("date match:", date)
        configstring.insert("\n", at: range.lowerBound)
    }
    startIndex = range.upperBound
}

print(configstring)  // "\n01/01/19 AAA BBB CCC DDD EEE FFF GGG HHH III JJJ KKK 0000 1111 0000 0000 1111 0000 0000 LLLL \n01/02/19 MMM NNN OOO PPP RRR SSS TTT UUU 0000 1111 1111 0000 1111 1111 0000 1111 0000 0000 WWWW \n"
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
  • using NSDataDetector was throwing me an error, however regular expression works like a charm! thank You so much! – KarolB Jul 13 '19 at 14:41
  • i have thicked green mark left of Your answer, thank You! – KarolB Jul 13 '19 at 14:43
  • I do not want to start new topic, but I have another question: by using same method which was provided by Leo Dabus how to remove all spaces between last string segment and new line symbol which was added near date segment? I have this: LLLL \n01/02/19 and I want this: LLLL\n01/02/19. Problem is that in my real string there are different number of spaces near each date segment. – KarolB Jul 13 '19 at 15:20
  • Do you mean trim white spaces at the end of the lines? – Leo Dabus Jul 13 '19 at 15:22
  • Yes I would like to trim whitespaces at the end of the lines, however if there is a method to find all spaces between known regular expression and nearest char other than space I would prefer this one, because I will probably need such function in near future. Thank You! – KarolB Jul 13 '19 at 15:25
  • `configstring = configstring.trimmingCharacters(in: .whitespaces) .replacingOccurrences(of: "\\s+\n", with: "\n", options: .regularExpression)` – Leo Dabus Jul 13 '19 at 15:30
  • You are very helpful and fast! I will give it a try. Thank You! – KarolB Jul 13 '19 at 15:32
  • you are welcome. `"\\s+\n"` will match any number of white spaces followed by a new line. – Leo Dabus Jul 13 '19 at 15:35
  • Your code of course works perfectly. My string is created by parsing data from html file. I noticed that I have rows of consecutive   non breaking spaces which is causing a lot of problems in my code. Another question raises how to using same principle as in previous question detect consecutive arrays of  's and replace them by only one whitespace (" ")? those arrays of   consists of different number of consecutive &nbsp:'s, sometimes one, sometimes six. Thanks – KarolB Jul 13 '19 at 18:54
  • Better to parse your html using NSAttributedString – Leo Dabus Jul 13 '19 at 19:39
  • i am actually using NSAttributedString.. I found regex calculator and got to answer of (?: +){2,} for two or more  's which is very good! – KarolB Jul 13 '19 at 19:43
  • use this extension https://stackoverflow.com/a/28132610/2303865 so you can do `"    ".html2String` which will return `"    "` – Leo Dabus Jul 13 '19 at 19:47
  • and for replacing multiple spaces for a single space `.replacingOccurrences(of: "\\s{2,}", with: " ", options: .regularExpression)` – Leo Dabus Jul 13 '19 at 19:59
  • Leo- You are very perceptive. You right, I was about to use NSAttributed string, I made extension according to link that You just shared, but finally I was not able to figure out how to call this function, so I ended up with removing html headers from html to text converted string. So let's make it work now. If my html data is stored as let htmldataflight how I should change call 'cell.detailTextLabel?.text = item.itemDescription.html2String' to work with my code? thanks... – KarolB Jul 13 '19 at 20:11