0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

CharacterをStrideableプロトコルに準拠させる一工夫【swift】

Last updated at Posted at 2024-09-14

はじめに

  • 前回の投稿につづいて、swiftの不甲斐なさのあまり、怒りにまかせて一工夫してしまった。

Character型の特徴

  • 競技プログラミングしてると、文字列(String)を扱うことが頻繁にあるけど、文字列を分解するため配列にすると、その要素はCharacter型になる。
let a = "a"
print(type(of:a)) // String

let abc = "abc"
let ary = Array(abc)
print(ary) // ["a", "b", "c"]
print(type(of:ary)) // Array<Character>
print(String(ary)) // "abc"

let c:Character = "c"
print(type(of:c)) // Character
// let cd:Character = "cd" -- error 二文字は駄目!
  • Character型の特徴については、上記コードのとおり。
  • で、Character型は、"a"の次は"b"という順序もあるから、こんなコードが可能かな?と思ったところ、イケたんだよ!
let az = "a" as Character ... "z" // -- この書き方は最新のswiftでは駄目みたい(詳細は、後述)
print(type(of:az)) // ClosedRange<Character>

print(az.contains("d")) // true
print(az.contains("D")) // false
  • ここまで来たら、当然、これイキますわ
let az = "a" as Character ... "z" // -- この書き方は最新のswiftでは駄目みたい(詳細は、後述)
for c in az {
    print(c)
}
-- error : protocol 'Sequence' requires that 'Character' conform to 'Strideable'
  • はい、出ました、クソ仕様によるエラー!Character型で作ったレンジはStrideableプロトコルに準拠してないからfor文に使えません!!!
  • 大事なことなので、もう一回言います。Character型で作ったレンジはStrideableプロトコルに準拠してないからfor文に使えません!!!
  • ふざけんな〜〜〜!!!(全国50人くらいの swiftで競技プログラムしている人達 の声)
  • なので、Character型で作ったレンジをfor文で使いたい人のために、このコードを捧げます。まぁ、swiftで競技プログラミングしてる人なら、...以下略

swiftで苦労している君に捧げるコード

  • Strideableは次の2つのメソッドが必須です。
    • advanced(by n: Int)
      • nズラした値を返す。例えば、"c".advanced(by:2) -> "e" のイメージ。
    • distance(to other: Self)
      • 2つの値の差を返す。例えば、"c".distance(to:"f") -> 3 のイメージ。
  • じゃあ、つくります。
extension Character: Strideable {
    public func advanced(by n: Int) -> Self {
        return Character(UnicodeScalar(Int(self.asciiValue!) + n)!)
    }
    public func distance(to other: Self) -> Int {
        return Int(other.asciiValue!) - Int(self.asciiValue!)
    }
}

let a_z = "a" as Character ... "z" // -- この書き方は最新のswiftでは駄目みたい(詳細は、後述)
for c in a_z {
    print(c,terminator:"") // abcdefghijklmnopqrstuvwxyz
}
print(Character("a").advanced(by:2)) // c
print(Character("a").distance(to:"d")) // 3
  • うむ、成功!!
  • でも、extensionの実装内容は意外と分かりづらいよね。文句はswift君に言ってくれ。一応説明すると、
    • .asciiValue
      • ASCIIコードを返します。オプショナル型のUInt8が返るので!を付けて、Int化が必要。
      • ちなみに、"あ".asciiValueはnilとなります。"あ"はascii文字じゃないからね。
    • UnicodeScalar
      • Characterのイニシャライザが、asciiコードを受け付けないから、一度、UnicodeScalarをかます必要がある。本当に無駄よね。でもまぁ、Characterさんの事情もあるから許してあげよう。
      • ちなみに、CharacterとUnicodeScalarの関係は、次を見て貰えば、なんとなく分かるだろうか。
      • そういえば、typealias UnicodeScalar = Unicode.Scalarです
        let ka = "\u{304B}" as Unicode.Scalar
        let daku = "\u{3099}" as Unicode.Scalar
        // let ka_daku = "\u{304B}\u{3099}" as Unicode.Scalar -- エラー
        let ga = "\u{304C}" as Unicode.Scalar
        print(ka,daku) // か ゙
        
        let ka_c = "\u{304B}" as Character
        let daku_c = "\u{3099}" as Character
        let ka_daku_c = "\u{304B}\u{3099}" as Character
        let ga_c = "\u{304C}" as Character
        print(ka_c,daku_c,ka_daku_c,ga_c) // か ゙ が が
        
        print(ka_daku_c == ga_c) // true
        
        let ka_num = Unicode.Scalar(0x304b)
        // let ka_c_num = Character(0x304b) -- エラー
        
        let ka_c_num = Character(Unicode.Scalar(0x304b)!)
        
        print(ka_num!) // か
        print(ka_c_num) // か
        
      • Characterは、"\u{304B}\u{3099}"と"\u{304C}" が一致するのがポイント高いよね。だからこそ、Characterは数値でイニシャライズできず、UnicodeScalarをかまさないと駄目なんだろうね。糞面倒。
      • ちなみに、このextensionは、a-zやA-Zではつかえるけど、ascii文字じゃない「あ〜ん」では使えないから注意してね。

注意!!!

Characterのレンジ生成で、最新のswiftでは、
× let a_z = "a" as Character ... "z"
 の表記は駄目になったみたいです。

「paiza.io」ではイケたけど、「atcoderの提出」ではアウト。

let a_z = ("a" as Character) ... "z"
let a_z = Character("a")..."z"
 ならイケます。

 駄目になった書き方の方が、スッキリしてて、オシャレで好きなのに...

さいごに

  • a-zをレンジに出来るなら、forのレンジでも使わせてくれ!
  • [a,c,e,...]のような、一つ飛ばしみたいな使い方をするつもりもないのに、Strideableに強制的に準拠させようとしないで欲しいです。
0
1
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?