Как использовать литеральные регулярные выражения Swift в операторах шаблона switch case?

Как использовать литеральные регулярные выражения Swift в операторах шаблона switch case?

Основываясь на примерах из слайдов презентации WWDC 2022, ожидается, что следующее скомпилируется и запустится нормально:

      import Foundation
import RegexBuilder

switch "abc" {
    case /\w+/:
        print("matched!")
    default:
        print("not matched.")
}

Однако возникает следующая ошибка:

Образец выражения типаRegex<Substring>не может соответствовать значениям типаString

Может лиswitch caseоператор с литеральным выражением регулярного выражения Swift каким-то образом модифицируется, чтобы он функционировал нормально? Как можно использовать новые возможности регулярных выражений Swift 5.7 в операторе шаблона switch case?

2 ответа

Из того, что я нашел, "сопоставление с регулярными выражениями вswitchоператор" не был реализован, потому что люди спорили о том, какой должна быть точная семантика. В случае, например,

      switch "---abc---" {
case /\w+/:
    print("foo")
default:
    print("bar")
}

в какой ветке должен выполняться оператор switch? Должен ли он считаться совпадением только в том случае, если вся строка соответствует регулярному выражению, или этого достаточно только для совпадения подстроки переключаемой строки? Другими словами, этоwholeMatchилиfirstMatch? Смотрите больше обсуждения здесь.

В конце концов, они не смогли прийти к выводу, и

Предложение было принято с изменениями (на данный момент изменения должны быть включены в подмножество).

Итак~=оператор не был добавлен дляRegex<Output>, поэтому вы не можете использовать его в коммутаторе.

Вы можете добавить его сами, если хотите, если можете выбрать между двумя семантиками :) Например:

      func ~=(regex: Regex<Substring>, str: String) -> Bool {
    // errors count as "not match"
    (try? regex.wholeMatch(in: str)) != nil
}

Можно ли каким-то образом изменить оператор switch case с литеральным выражением регулярного выражения Swift, чтобы он работал нормально?

Да, используйтеcase let … where …подход с возможностью регулярных выражений, выпущенной, начиная с Swift 5.7.

Классический пример - "классический" пример регулярного выражения, где/^…$/может использоваться для соответствия полной строке:

      extension String {
    func classic(_ regex: Regex<Substring>) -> Bool {
        // errors count as "not match"
        (try? regex.firstMatch(in: self)) != nil
    }    
}


switch "---abc---" {
    case let s where s.classic(/^\w+$/):
        print("entire line contains alphanumerics: '\(s)'")
    case let s where s.classic(/\w+/):
        print("alphanumerics found in string: '\(s)'")
    default:
        print("no alphanumerics found")
}

Пример полного совпадения — подход регулярного выражения «только полное совпадение», когда частичное совпадение невозможно:

      extension String {
    func whole(_ regex: Regex<Substring>) -> Bool {
        // errors count as "not match"
        (try? regex.wholeMatch(in: self)) != nil
    }
}

switch "---abc---" {
    case let s where s.whole(/\w+/):
        print("all alphanumerics: '\(s)'")
    default:
        print("no match for /\\w+/")
}

В итоге я использовал подход «Классический пример» вместо примера «Только полное совпадение» иподходит по следующим причинам:

  • func ~=- возможно, будет определен Swift в будущем. Возможная путаница в будущем.
  • Пример полного совпадения — не поддерживает как частичное, так и полное совпадение. Менее выразительный.
  • Классический пример
    • листья~=undefined, что позволяет возможное определение Swift в будущем. Избегает возможной путаницы в будущем.
    • поддерживает как частичные, так и полные совпадения. Более выразительный.
    • ^…$прямо указано для полного совпадения строк. Более читаемый.
Другие вопросы по тегам