Swift中用于匹配字符串子串的switch语句

38

我想从一个变量中获取一些值。这个变量将包含天气描述,我想要查询特定的词语以便显示不同的图像(比如太阳、雨等)。 问题是我有以下代码:

    if self.descriptionWeather.description.rangeOfString("Clear") != nil
{
    self.imageWeather.image = self.soleadoImage
}
if self.descriptionWeather.description.rangeOfString("rain") != nil
{
    self.imageWeather.image = self.soleadoImage
}
if self.descriptionWeather.description.rangeOfString("broken clouds") != nil
{
    self.imageWeather.image = self.nubladoImage
}

因为当我尝试添加一个“OR”条件时,Xcode会给我一些奇怪的错误。

是否可以使用switch语句?或者有人知道如何向if子句添加OR条件吗?


4
你是如何添加“OR”条件的?你遇到了什么奇怪的错误? - Thilo
例如,如果我想将第一个和第二个放在同一个if语句中: if self.descriptionWeather.description.rangeOfString("晴朗") != nil | self.descriptionWeather.description.rangeOfString("多云") != nil { self.imageWeather.image = self.soleadoImage } 而错误是:非关联运算符与相同优先级的运算符相邻,并且无法调用'!=',其参数列表类型为'($T17, NilLiteralConvertible)'。 - LPS
7个回答

98

今天我遇到了类似的问题,发现这个问题自从Swift 1以来就没有更新过!以下是我在Swift 4中解决它的方法:

switch self.descriptionWeather.description {
case let str where str.contains("Clear"):
    print("clear")
case let str where str.contains("rain"):
    print("rain")
case let str where str.contains("broken clouds"):
    print("broken clouds")
default:
    break
}

6
这个解决方案/答案比被采纳的答案好得多。 - L A

24

Swift 5 解决方案

func weatherImage(for identifier: String) -> UIImage? {
    switch identifier {
    case _ where identifier.contains("Clear"),
         _ where identifier.contains("rain"):
        return self.soleadoImage
    case _ where identifier.contains("broken clouds"):
        return self.nubladoImage
    default: return nil
    }
}

13
你可以使用值绑定和 `where` 子句的 switch 语句来实现这一点。但是,在此之前请将字符串转换为小写!
var desc = "Going to be clear and bright tomorrow"

switch desc.lowercaseString as NSString {
case let x where x.rangeOfString("clear").length != 0:
    println("clear")
case let x where x.rangeOfString("cloudy").length != 0:
    println("cloudy")
default:
    println("no match")
}

// prints "clear"

6
如果您需要经常进行此操作,可以实现自定义的 ~= 运算符来定义子字符串匹配。它支持以下简洁明了的语法:
switch "abcdefghi".substrings {
    case "def": // calls `"def" ~= "abcdefghi".substrings`
        print("Found substring: def") 
    case "some other potential substring":
        print("Found \"some other potential substring\"")
    default: print("No substring matches found")
}

实现:

import Foundation

public struct SubstringMatchSource {
    private let wrapped: String
    
    public init(wrapping wrapped: String) {
        self.wrapped = wrapped
    }
    
    public func contains(_ substring: String) -> Bool {
        return self.wrapped.contains(substring)
    }
    
    public static func ~= (substring: String, source: SubstringMatchSource) -> Bool {
        return source.contains(substring)
    }
}

extension String {
    var substrings: SubstringMatchSource {
        return SubstringMatchSource(wrapping: self)
    }
}

我也在想类似的事情 :) 把字符串封装成自定义类型是个好主意。或许应该为StringProtocol定义它? - Martin R
@MartinR 我尝试过了,但我认为在StringProtocol上不可用contains方法,并且我遇到了一些其他的泛型错误。你能试试吗? - Alexander
可以在Swift 5中编译,但无法在Swift 4中编译。 - Martin R
1
@MartinR 如果你将结构体泛型类型Index限制为String.Index,如下所示:public struct SubstringMatchSource<S: StringProtocol> where S.Index == String.Index {extension StringProtocol where Index == String.Index { 它在Swift 4中可以编译。 - Leo Dabus
@LeoDabus 这个限制有多严格?有哪些非字符串类型适用?子字符串? - Alexander
2
@LeoDabus:确实就是这样。-这些限制已经在Swift 5的stdlib中添加了。我记得有一段时间在Swift论坛上讨论过它,但现在找不到它了。如果我没记错的话,所有符合StringProtocol的类型都应该满足这个限制,并且在stdlib中不需要它被认为是一种遗漏(这已经在Swift 5中得到了修复)。 - Martin R

5

Swift语言有两种OR运算符 - 位运算符|(单竖线)和逻辑运算符||(双竖线)。在这种情况下,您需要使用逻辑OR:

if self.descriptionWeather.description.rangeOfString("Clear") != nil || self.descriptionWeather.description.rangeOfString("clear") != nil {
    self.imageWeather.image = self.soleadoImage
}

与Objective-C 不同,你可以通过进行按位OR操作来获得略微不同的运行时语义,但在Swift 中,上面的表达式需要进行逻辑OR操作。

0
我建议使用字典,将你要搜索的子字符串与相应的图像进行映射。
func image(for weatherString: String) -> UIImage? {
    let imageMapping = [
        "Clear": self.soleadoImage,
        "rain": self.soleadoImage,
        "broken clouds": self.nubladoImage]
    return imageMapping.first { weatherString.contains($0.key) }?.value
}

一个字典可以给你灵活性,添加新映射很容易做到。

-1

这个链接还描述了重载操作符~=,它实际上被switch语句用于匹配情况以允许您匹配正则表达式。


2
很棒的故事,但是链接已经失效了。 - Alexandre G

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