What are these types with regular expressions?


(晓敏 褚) #1

I’m writing a program with regular expressions, and I’m finding it extremely hard to code with these in swift. I got a [TextCheckingResult] from the matching function, and there is no document on what TextCheckingResult is and how could I work with it. And when I try to use range to get a substring, I got a Range<Int>, but the substring:with: method requies a Range<Index>. But there is no way I could find any information about the type(or protocol?) Index, and passing a Int fails.
What are they, and how can I work with them?


(Saagar Jha) #2

Swift String indexing and sub scripting is different than other languages.
Instead of using Ints, Strings use their own Indexes (a String.Index). To
get an index, you can use the String's startIndex property and then use
advancedBy on it. The Swift Programming Language has more details:
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html#//apple_ref/doc/uid/TP40014097-CH7-ID285

···

On Sat, Aug 6, 2016 at 04:26 晓敏 褚 <swift-users@swift.org> wrote:

I’m writing a program with regular expressions, and I’m finding it
extremely hard to code with these in swift. I got a [TextCheckingResult]
from the matching function, and there is no document on what
TextCheckingResult is and how could I work with it. And when I try to use
range to get a substring, I got a Range<Int>, but the substring:with:
method requies a Range<Index>. But there is no way I could find any
information about the type(or protocol?) Index, and passing a Int fails.
What are they, and how can I work with them?
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Brent Royal-Gordon) #3

"The Swift Programming Language" discusses this in more detail, but briefly: String indexing is much more complicated than NSString might make you think. For instance, the character 𠀋 is spread across two "indices", because it is in the Supplementary Ideographic Plane of Unicode. Moreover, there are actually several different mechanisms that can make a single "character" actually take up multiple indices. To model this, a Swift String offers several views (`characters`, `unicodeScalars`, `utf16`, and `utf8`), each of which handles indices in a different way. In Swift 2, each of these has its own `Index` type; I believe the plan was for Swift 3 to use one Index type shared between all views, but I'm not sure if that change will make the release version.

`NSString`, on the other hand, uses bare `Int`s interpreted a UTF-16 indices. So the way to convert is to translate the `Int` into a `String.UTF16Index`, and then if you want to go from there, further translate the `UTF16Index` into `String.Index`. (This second step can fail if, for instance, the `UTF16Index` points to the second index within 𠀋.) You can do that with an extension like this one:

  // Swift 3:
  extension String.UTF16View {
    func convertedIndex(_ intIndex: Int) -> Index {
      return index(startIndex, offsetBy: intIndex)
    }
    func convertedRange(_ intRange: Range<Int>) -> Range<Index> {
      let lower = convertedIndex(intRange.lowerBound)
      let offset = intRange.upperBound - intRange.lowerBound
      let upper = index(lower, offsetBy: offset)
      
      return lower ..< upper
    }
  }
  extension String {
    func convertedIndex(_ intIndex: Int) -> Index? {
      let utfIndex = utf16.convertedIndex(intIndex)
      return utfIndex.samePosition(in: self)
    }
    func convertedRange(_ intRange: Range<Int>) -> Range<Index>? {
      let utfRange = utf16.convertedRange(intRange)
      guard let lower = utfRange.lowerBound.samePosition(in: self),
        let upper = utfRange.upperBound.samePosition(in: self) else {
        return nil
      }
      return lower ..< upper
    }
  }

  // Swift 2:
  extension String.UTF16View {
    func convertedIndex(intIndex: Int) -> Index {
      return startIndex.advancedBy(intIndex)
    }
    func convertedRange(intRange: Range<Int>) -> Range<Index> {
      let lower = convertedIndex(intRange.startIndex)
      let offset = intRange.endIndex - intRange.startIndex
      let upper = lower.advancedBy(offset)
      
      return lower ..< upper
    }
  }
  extension String {
    func convertedIndex(intIndex: Int) -> Index? {
      let utfIndex = utf16.convertedIndex(intIndex)
      return utfIndex.samePositionIn(self)
    }
    func convertedRange(intRange: Range<Int>) -> Range<Index>? {
      let utfRange = utf16.convertedRange(intRange)
      guard let lower = utfRange.startIndex.samePositionIn(self),
        let upper = utfRange.startIndex.samePositionIn(self) else {
        return nil
      }
      return lower ..< upper
    }
  }

Use it like this:

  let range: Range<Int> = …
  
  // If you want to use String.UTF16Index:
  let convertedRange = string.utf16.convertedRange(range)
  print(string.utf16[convertedRange])
  
  // If you want to use String.Index:
  if let convertedRange = string.convertedRange(range) {
    print(string[convertedRange])
  }
  else {
    print("[Invalid range]")
  }

Hope this helps,

···

On Aug 6, 2016, at 5:25 AM, 晓敏 褚 via swift-users <swift-users@swift.org> wrote:

And when I try to use range to get a substring, I got a Range<Int>, but the substring:with: method requies a Range<Index>. But there is no way I could find any information about the type(or protocol?) Index, and passing a Int fails.
What are they, and how can I work with them?

--
Brent Royal-Gordon
Architechies


(Zhao Xin) #4

TextCheckingResult i
​s​
NSTextCheckingResult
<https://developer.apple.com/reference/foundation/nstextcheckingresult#>。

​Zhaoxin​

···

On Sat, Aug 6, 2016 at 8:25 PM, 晓敏 褚 <swift-users@swift.org> wrote:

I’m writing a program with regular expressions, and I’m finding it
extremely hard to code with these in swift. I got a [TextCheckingResult]
from the matching function, and there is no document on what
TextCheckingResult is and how could I work with it. And when I try to use
range to get a substring, I got a Range<Int>, but the substring:with:
method requies a Range<Index>. But there is no way I could find any
information about the type(or protocol?) Index, and passing a Int fails.
What are they, and how can I work with them?
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users