Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
2.2k views
in Technique[技术] by (71.8m points)

ios - What is the correct length: argument to provide to NSRange for NSRegularExpression using a (Swift) String?

I'm confused on how to use the NSRegularExpression class in Swift, especially the :length parameter of NSRange.

Some tutorials say that NSRegularExpression should only be applied to NSString instances, while others say it's OK to apply it to (Swift) string instances as long as you provide utf8.count or utf16.count to :length parameter of NSRange:

var str : String = "#tweak #wow #gaming" 
if let regex = try? NSRegularExpression(pattern: "#[a-z0-9]+", options: .caseInsensitive) {
    regex.matches(in: str, options: [], range: NSRange(location: 0, length: str.utf8.count)).map {
        print(str.substring(with: $0.range))
    }
}

The following are quotes from this source:

Due to the way strings are handled differently in Swift and Objective-C, you will need to provide the NSRange instance with a string length from NSString, and not from String.

This is, roughly speaking, because NSString uses fixed-width encoding and String uses variable-width encoding.

Furthermore, is the following documentation really the best Apple can do with respect to documenting the NSRegularExpression class in Swift?

https://developer.apple.com/documentation/foundation/nsregularexpression

I'd at least expect a list of properties and methods of the class, but it only show some examples. Is there any more elaborate documentation?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The utf16 count is correct, not the utf8 count. Or, best, use the convenience initializers, which convert a Range of String.Index to a NSRange:

let range = NSRange(str.startIndex..., in: str)

And to convert NSRange to String.Range:

let range = Range(nsRange, in: str)

Thus, putting that together:

let str = "#tweak #wow #gaming" 
if let regex = try? NSRegularExpression(pattern: "#[a-z0-9]+", options: .caseInsensitive) {
    let nsRange = NSRange(str.startIndex..., in: str)
    let strings = regex.matches(in: str, range: nsRange).compactMap {
        Range($0.range, in: str).map { str[$0] }
    }
    print(strings)
}

See WWDC 2017 Efficient Interactions with Frameworks, which talks about (a) our historical use of UTF16 when dealing with ranges; and (b) the fact that we don’t have to do that any more.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...