Swift的startsWith方法是什么?

176

在Swift中是否有类似于startsWith()方法的东西?

我想要检查一个字符串是否以另一个字符串开头。我还希望它不区分大小写。

你可能已经注意到,我只是想做一个简单的搜索功能,但我似乎在这方面失败了。

这就是我想要的:

输入“sa”应该给我“San Antonio”、“Santa Fe”等结果。 输入“SA”、“Sa”甚至“sA”也应返回“San Antonio”或“Santa Fe”。

我曾经使用过:

self.rangeOfString(find, options: NSStringCompareOptions.CaseInsensitiveSearch) != nil 

iOS9之前,一切正常。但升级到iOS9后,搜索功能出现问题,变得区分大小写。

    var city = "San Antonio"
    var searchString = "san "
    if(city.rangeOfString(searchString, options: NSStringCompareOptions.CaseInsensitiveSearch) != nil){
        print("San Antonio starts with san ");
    }

    var myString = "Just a string with san within it"

    if(myString.rangeOfString(searchString, options: NSStringCompareOptions.CaseInsensitiveSearch) != nil){
        print("I don't want this string to print bc myString does not start with san ");
    }

你能给出一个具体的例子,说明使用CaseInsensitiveSearch的rangeOfString无法按预期工作吗?我已在iOS 9模拟器中进行了测试,并且它对我有效。 - Martin R
7个回答

418

使用 hasPrefix 代替 startsWith

示例:

"hello dolly".hasPrefix("hello")  // This will return true
"hello dolly".hasPrefix("abc")    // This will return false

5
OP要求不区分大小写,而您的回答区分大小写。 - Cœur
17
在比较之前使用 "string".lowercased() 将字符串转换为小写非常容易。 - TotoroTotoro

14

这是一个Swift扩展实现startsWith的示例:

extension String {

  func startsWith(string: String) -> Bool {

    guard let range = rangeOfString(string, options:[.AnchoredSearch, .CaseInsensitiveSearch]) else {
      return false
    }

    return range.startIndex == startIndex
  }

}

示例用法:

var str = "Hello, playground"

let matches    = str.startsWith("hello") //true
let no_matches = str.startsWith("playground") //false

14

针对不区分大小写的前缀匹配问题,具体回答如下:

在纯Swift中(大多数情况下建议使用)

extension String {
    func caseInsensitiveHasPrefix(_ prefix: String) -> Bool {
        return lowercased().hasPrefix(prefix.lowercased())
    }
}
或者:
extension String {
    func caseInsensitiveHasPrefix(_ prefix: String) -> Bool {
        return lowercased().starts(with: prefix.lowercased())
    }
}

注意:对于空前缀"",两种实现都将返回true

使用Foundation range(of:options:)

extension String {
    func caseInsensitiveHasPrefix(_ prefix: String) -> Bool {
        return range(of: prefix, options: [.anchored, .caseInsensitive]) != nil
    }
}

注意:对于空前缀"",它将返回false

使用正则表达式可能会很丑陋(我见过...)

extension String {
    func caseInsensitiveHasPrefix(_ prefix: String) -> Bool {
        guard let expression = try? NSRegularExpression(pattern: "\(prefix)", options: [.caseInsensitive, .ignoreMetacharacters]) else {
            return false
        }
        return expression.firstMatch(in: self, options: .anchored, range: NSRange(location: 0, length: characters.count)) != nil
    }
}

注意:如果前缀为空字符串"",它将返回false


10

编辑:更新为 Swift 3 版本。

Swift 的 String 类确实有区分大小写的方法 hasPrefix(),但如果你想进行不区分大小写的搜索,可以使用 NSString 的方法 range(of:options:)

注意:默认情况下,NSString 方法是不可用的,但如果你 import Foundation,它们就可用了。

所以:

import Foundation
var city = "San Antonio"
var searchString = "san "
let range = city.range(of: searchString, options:.caseInsensitive)
if let range = range {
    print("San Antonio starts with san at \(range.startIndex)");
}
选项可以给出为.caseInsensitive[.caseInsensitive]的形式。如果您想使用其他选项,例如:

[.caseInsensitive, .option2, .option3]
[.caseInsensitive, .option2, .option3]
let range = city.range(of: searchString, options:[.caseInsensitive, .backwards])

这种方法的优点在于可以与搜索一起使用其他选项,例如.diacriticInsensitive搜索。仅通过在字符串上使用.lowercased()无法达到相同的结果。


6
在Swift 4中,将会引入func starts<PossiblePrefix>(with possiblePrefix: PossiblePrefix) -> Bool where PossiblePrefix : Sequence, String.Element == PossiblePrefix.Element
示例用法:
let a = 1...3
let b = 1...10

print(b.starts(with: a))
// Prints "true"

3

在Swift 4中使用扩展

我的extension-example包含3个函数:检查一个字符串是否以子字符串开头,将一个字符串结束为一个子字符串和检查一个字符串是否包含一个子字符串。

如果您想忽略字符"A"或"a",则将isCaseSensitive参数设置为false,否则设置为true。

有关它的工作原理的更多信息,请参见代码中的注释。

代码:

    import Foundation

    extension String {
        // Returns true if the String starts with a substring matching to the prefix-parameter.
        // If isCaseSensitive-parameter is true, the function returns false,
        // if you search "sA" from "San Antonio", but if the isCaseSensitive-parameter is false,
        // the function returns true, if you search "sA" from "San Antonio"

        func hasPrefixCheck(prefix: String, isCaseSensitive: Bool) -> Bool {

            if isCaseSensitive == true {
                return self.hasPrefix(prefix)
            } else {
                var thePrefix: String = prefix, theString: String = self

                while thePrefix.count != 0 {
                    if theString.count == 0 { return false }
                    if theString.lowercased().first != thePrefix.lowercased().first { return false }
                    theString = String(theString.dropFirst())
                    thePrefix = String(thePrefix.dropFirst())
                }; return true
            }
        }
        // Returns true if the String ends with a substring matching to the prefix-parameter.
        // If isCaseSensitive-parameter is true, the function returns false,
        // if you search "Nio" from "San Antonio", but if the isCaseSensitive-parameter is false,
        // the function returns true, if you search "Nio" from "San Antonio"
        func hasSuffixCheck(suffix: String, isCaseSensitive: Bool) -> Bool {

            if isCaseSensitive == true {
                return self.hasSuffix(suffix)
            } else {
                var theSuffix: String = suffix, theString: String = self

                while theSuffix.count != 0 {
                    if theString.count == 0 { return false }
                    if theString.lowercased().last != theSuffix.lowercased().last { return false }
                    theString = String(theString.dropLast())
                    theSuffix = String(theSuffix.dropLast())
                }; return true
            }
        }
        // Returns true if the String contains a substring matching to the prefix-parameter.
        // If isCaseSensitive-parameter is true, the function returns false,
        // if you search "aN" from "San Antonio", but if the isCaseSensitive-parameter is false,
        // the function returns true, if you search "aN" from "San Antonio"
        func containsSubString(theSubString: String, isCaseSensitive: Bool) -> Bool {

            if isCaseSensitive == true {
                return self.range(of: theSubString) != nil
            } else {
                return self.range(of: theSubString, options: .caseInsensitive) != nil
            }
        }
    }

使用示例:

检查字符串是否以"TEST"开头:

    "testString123".hasPrefixCheck(prefix: "TEST", isCaseSensitive: true) // Returns false
    "testString123".hasPrefixCheck(prefix: "TEST", isCaseSensitive: false) // Returns true

检查字符串是否以“test”开头:

    "testString123".hasPrefixCheck(prefix: "test", isCaseSensitive: true) // Returns true
    "testString123".hasPrefixCheck(prefix: "test", isCaseSensitive: false) // Returns true

检查字符串是否以“G123”结尾:
    "testString123".hasSuffixCheck(suffix: "G123", isCaseSensitive: true) // Returns false
    "testString123".hasSuffixCheck(suffix: "G123", isCaseSensitive: false) // Returns true

检查字符串是否以"g123"结尾:

    "testString123".hasSuffixCheck(suffix: "g123", isCaseSensitive: true) // Returns true
    "testString123".hasSuffixCheck(suffix: "g123", isCaseSensitive: false) // Returns true

检查字符串是否包含“RING12”:

    "testString123".containsSubString(theSubString: "RING12", isCaseSensitive: true) // Returns false
    "testString123".containsSubString(theSubString: "RING12", isCaseSensitive: false) // Returns true

检查字符串是否包含"ring12":
    "testString123".containsSubString(theSubString: "ring12", isCaseSensitive: true) // Returns true
    "testString123".containsSubString(theSubString: "ring12", isCaseSensitive: false) // Returns true

1

Swift 3 版本:

func startsWith(string: String) -> Bool {
    guard let range = range(of: string, options:[.caseInsensitive]) else {
        return false
    }
    return range.lowerBound == startIndex
}

可以使用.anchored来提高速度。请查看我的回答或者Oliver Atkinson的回答。 - Cœur

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接