如何定义自定义运算符以处理swift中的string.index范围?

发布于 2025-01-29 09:31:06 字数 1377 浏览 3 评论 0原文

我发现使用string.index确实需要大量Swift中的代码,尤其是当涉及range> range Swift没有的方法时。就像上面的代码中,我不想要开放范围(两者都独家)。因此,我想知道我是否可以扩展字符串range或简化它的内容。在以下代码中,我已经知道startIndexendIndex是类型string.index.indexstartIndex ..< endIndIndex是类型range< string.index>。但是,当我扩展string.index时,我想定义一种static func>。<的方法。 (lhs:string.index,rhs:string.index) - > range< string.index>,但是我失败了,因为没有方法可以踩踏string.index上下。

let startIndex = str.index(str.firstIndex(of: "[") ?? str.startIndex, offsetBy: 1)
let endIndex = str.firstIndex(of: "]") ?? str.startIndex
let subStr = str[startIndex..<endIndex]

我想在下面定义运营商。使用间隔表示法,如果本机方法b等同于[a,b]和a ..&lt; b等效于[a,b),等于(a,b)和(a,, B]。

let startIndex = str.firstIndex(of: "[") ?? str.startIndex
let endIndex = str.firstIndex(of: "]") ?? str.startIndex
let subStr1 = str[startIndex...endIndex]    // [a, b]
let subStr3 = str[startIndex..<endIndex]    // [a, b)
let subStr2 = str[startIndex>.<endIndex]    // (a, b)
let subStr4 = str[startIndex>..endIndex]    // (a, b]

I find using String.Index really needs a lot of code in Swift, especially when it comes to methods of Range Swift doesn't have. Like in above code where I don't want an open range (both bounds exclusive). So I wonder if I can extend String or Range or something to simplify it. In the following code, I already know that startIndex and endIndex are of type String.Index, and startIndex..<endIndex is of type Range<String.Index>. But when I extend String.Index, I'd like to define a method like static func >.< (lhs: String.Index, rhs: String.Index) -> Range<String.Index>, but I failed because there's no method to step String.Index up or down.

let startIndex = str.index(str.firstIndex(of: "[") ?? str.startIndex, offsetBy: 1)
let endIndex = str.firstIndex(of: "]") ?? str.startIndex
let subStr = str[startIndex..<endIndex]

I want to define operators like below. To clarify them using interval notation, if native method a...b is equivalent to [a, b] and a..<b is equivalent to [a, b), what is the equivalent of (a, b) and (a,b].

let startIndex = str.firstIndex(of: "[") ?? str.startIndex
let endIndex = str.firstIndex(of: "]") ?? str.startIndex
let subStr1 = str[startIndex...endIndex]    // [a, b]
let subStr3 = str[startIndex..<endIndex]    // [a, b)
let subStr2 = str[startIndex>.<endIndex]    // (a, b)
let subStr4 = str[startIndex>..endIndex]    // (a, b]

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

小红帽 2025-02-05 09:31:06

编辑:而是请参见第二代码示例!请忽略第一个街区;我没有仔细阅读这个问题,因此这不是一个相关的解决方案。

编辑2:还请查看下面的第一个评论,以获取第一个示例的主要警告的示例。它对于包含表情符号的字符串无法正常工作。归功于Leo Dabus的这一发现。


该代码可能会执行您要寻找的内容,但在所有情况下我都不能保证其可靠性。

它的作用是进行常规的半开整个整数范围(表单a ..&lt; b)和一个特定的字符串(因为,正如Matt在他的评论中提到的那样,Swift String Indices Don' t涉及类字符串,仅与某些特定的字符串),并返回该特定字符串的开放范围。

实际上,它只是将其从包容性更改为独家的下限中增加了1个。

import Foundation

// Returns a Range of 'String.Index'es where both upper and lower bounds are exclusive.
extension Range {
    // Here, the upper bound of the range was already exclusive, so don't subtract 1 from it.  Only add 1 to the lower bound.
    static func OpenRange(string: String, range: Range<Int>) -> Range<String.Index> {
        return Range<String.Index>(uncheckedBounds: (String.Index(utf16Offset: range.lowerBound + 1, in: string), String.Index(utf16Offset: range.upperBound, in: string)))
    }
}

let theString = "abcdefg"
let endIndex = theString.index(theString.startIndex, offsetBy: 5)
let range: Range<String.Index> = theString.startIndex..<endIndex

let openRange = Range<String.Index>.OpenRange(string: theString, range: 0..<5)
print(theString[range]) // prints 'abcde'
print(theString[openRange]) // prints 'bcde'

参考:

我上面的示例并不真正符合您要问的特定情况,因为我是从已经开始的代码开始的,并且试图“适应”这种情况。我的坏!我相信这是一个更好的选择:

// Returns a Range of 'String.Index'es between two specified characters in the string (as exclusive bounds)
extension Range {
    // Here, the upper bound of the range was already exclusive, so don't subtract 1 from it.  Only add 1 to the lower bound.
    static func OpenRange(string: String, from: String, to: String) -> Range<String.Index> {
        // The 'firstIndex' method expects a Character, not a String, so you need a type cast here
        let lowerInclusive = string.firstIndex(of: Character(from))!
        let lowerExclusive = string.index(lowerInclusive, offsetBy: 1)
        let upperExclusive = string.firstIndex(of: Character(to))!
        return Range<String.Index>(uncheckedBounds: (lowerExclusive, upperExclusive))
    }
}

let theString = "[10:02.11]"
let openRange1 = Range<String.Index>.OpenRange(string: theString, from: "[", to: ":")
let openRange2 = Range<String.Index>.OpenRange(string: theString, from: ":", to: "]")

print(theString[openRange1]) // prints '10'
print(theString[openRange2]) // prints '02.11'

Edit: See the second code example instead! Please disregard the first block; I didn't read the question as carefully as I should have, so it is not a relevant solution.

Edit 2: Also look at the first comment below this answer for an example of a major caveat of the first example. It does not work correctly for strings which contain emojis. Credit to Leo Dabus for this discovery.


This code might do what you're looking for, but I can't guarantee its reliability in all cases.

What it does is take a regular half-open range of integers (of the form a..<b) and a specific string (because, as matt mentioned in his comment, Swift string indices don't pertain to the class String, only to some particular string), and returns an open range of indices for that particular string.

In effect, it just adds 1 to the lower bound to change it from inclusive to exclusive.

import Foundation

// Returns a Range of 'String.Index'es where both upper and lower bounds are exclusive.
extension Range {
    // Here, the upper bound of the range was already exclusive, so don't subtract 1 from it.  Only add 1 to the lower bound.
    static func OpenRange(string: String, range: Range<Int>) -> Range<String.Index> {
        return Range<String.Index>(uncheckedBounds: (String.Index(utf16Offset: range.lowerBound + 1, in: string), String.Index(utf16Offset: range.upperBound, in: string)))
    }
}

let theString = "abcdefg"
let endIndex = theString.index(theString.startIndex, offsetBy: 5)
let range: Range<String.Index> = theString.startIndex..<endIndex

let openRange = Range<String.Index>.OpenRange(string: theString, range: 0..<5)
print(theString[range]) // prints 'abcde'
print(theString[openRange]) // prints 'bcde'

Reference: https://www.avanderlee.com/swift/ranges-explained/

The example I had above doesn't really fit the specific case you were asking about though, as I was starting from code I already had and was trying to 'adapt' it to this situation. My bad! I believe this is a better alternative:

// Returns a Range of 'String.Index'es between two specified characters in the string (as exclusive bounds)
extension Range {
    // Here, the upper bound of the range was already exclusive, so don't subtract 1 from it.  Only add 1 to the lower bound.
    static func OpenRange(string: String, from: String, to: String) -> Range<String.Index> {
        // The 'firstIndex' method expects a Character, not a String, so you need a type cast here
        let lowerInclusive = string.firstIndex(of: Character(from))!
        let lowerExclusive = string.index(lowerInclusive, offsetBy: 1)
        let upperExclusive = string.firstIndex(of: Character(to))!
        return Range<String.Index>(uncheckedBounds: (lowerExclusive, upperExclusive))
    }
}

let theString = "[10:02.11]"
let openRange1 = Range<String.Index>.OpenRange(string: theString, from: "[", to: ":")
let openRange2 = Range<String.Index>.OpenRange(string: theString, from: ":", to: "]")

print(theString[openRange1]) // prints '10'
print(theString[openRange2]) // prints '02.11'
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文