Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Rangeと仲良くなる15分 with String.Index & Unicode

satoshin21
September 17, 2017

Rangeと仲良くなる15分 with String.Index & Unicode

Understanding Range of iOS with String.Index & Unicode
iOSDC2017

9/17 15:10
@早稲田大学理工学部 西早稲田キャンパス 63号館

satoshin21

September 17, 2017
Tweet

More Decks by satoshin21

Other Decks in Technology

Transcript

  1. Copyright © 2017 eureka, Inc. All rights reserved. Understanding Range

    of iOS with String.Index & Unicode Rangeͱ஥ྑ͘ͳΔ15෼ with String.Index & Unicode
  2. Copyright © 2017 eureka, Inc. All rights reserved. 5 Introduce

     FVSFLB *OD  1BJSTJ04"QQMJDBUJPO&OHJOFFS  "VUIPSPG$IBJO"OJNBUJPO-JCSBSZl"OJNBz  4UBS0WFS @satoshin21
  3. Copyright © 2017 eureka, Inc. All rights reserved. 6 ͜ͷSessionͷ໨ඪ

     4XJGU3BOHFɺ/43BOHFͷجૅʹ͍ͭͯཧղ͢Δ  4XJGU ٴͼ4XJGUͷ௥Ճ࢓༷
  4. Copyright © 2017 eureka, Inc. All rights reserved. 7 ͜ͷSessionͷ໨ඪ

     จࣈྻૢ࡞࣌ͷ3BOHFͱ஥ྑ͘ͳΔ  ଟ෼3BOHFͱ஥ྑ͘ͳΕͳ͍ͷ͸จࣈྻૢ࡞ͷ͍ͤ  Կނ3BOHFͱ4USJOH ओʹ4USJOH*OEFY Λ࢖͏ͱਏ͍ͷ͔  4XJGUͱ/4ʹ͓͚Δ6OJDPEFͷجૅʹ͍ͭͯཧղ͢Δ  4XJGUͱ4XJGUʹ͓͚Δɺ3BOHFΛ࢖ͬͨจࣈྻૢ࡞ͷͭ·͖ͮϙΠ ϯτΛ֬ೝ͢Δ
  5. Copyright © 2017 eureka, Inc. All rights reserved. 10 Swift.Rangeͷجຊ

     3BOHF#PVOE  $PVOUBCMF3BOHF#PVOE  $MPTFE3BOHF#PVOE  $PVOUBCMF$MPTFE3BOHF#PVOE  1BSUJBM3BOHF'SPN#PVOE/FX  1BSUJBM3BOHF5ISPVHI#PVOE/FX  ʜ
  6. Copyright © 2017 eureka, Inc. All rights reserved. 11 Swift.Range

    )BMG0QFO ൒։۠ؒ $MPTFE ด۠ؒ 6O$PVOUBCMF 3BOHF#PVOE $MPTFE3BOHF#PVOE $PVOUBCMF $PVOUBCMF3BOHF #PVOE $PVOUBCMF$MPTFE3BOHF #PVOE
  7. Copyright © 2017 eureka, Inc. All rights reserved. 12 Countable

    or UnCountable ? // Countable let countableRange1 = 0...0 let countableRange2 = 10..<100 // UnCountable let unCountableRange1 = 0.2...19.5 let unCountableRange2 = 0..<20.0
  8. Copyright © 2017 eureka, Inc. All rights reserved. 13 Countable

    or UnCountable ? // Countable let countableRange1 = 0...0 let countableRange2 = 10..<100 // UnCountable let unCountableRange1 = 0.2...19.5 let unCountableRange2 = 0..<20.0
  9. Copyright © 2017 eureka, Inc. All rights reserved. 14 Countable

    or UnCountable ?  $PVOUBCMF4USJEFBCMFQSPUPDPMʹ४ڌ͍ͯ͠Δ͔  4USJEFBCMF4USJEF4JHOFE*OUFHFS  *OUࠁΈͰલޙૢ࡞ՄೳͰ͋Δ͔ʁ  'MPBU %PVCMFͳͲͷ৔߹͸ࠁΉࣄ͕Ͱ͖ͳ͍ͷͰɺ$PVOUBCMF3BOHFʹ Ͱ͖ͳ͍  *OU     'MPBUˡXIBU`TOFYU   
  10. Copyright © 2017 eureka, Inc. All rights reserved. 15 Range

    or ClosedRange (ด۠ؒ or ൒։۠ؒ)? // Range(半開区間) let range1 = 0..<10 let range2 = 0.0..<10.0 // ClosedRange(閉区間) let closedRange1 = 0...10 let closedRange2 = 0.0...10.0
  11. Copyright © 2017 eureka, Inc. All rights reserved. 16 Range

    or ClosedRange (ด۠ؒ or ൒։۠ؒ)? // Range(半開区間) let range1 = 0..<10 let range2 = 0.0..<10.0 // ClosedRange(閉区間) let closedRange1 = 0...10 let closedRange2 = 0.0...10.0
  12. Copyright © 2017 eureka, Inc. All rights reserved. 17 Range

    or ClosedRange (ด۠ؒ or ൒։۠ؒ)?  $MPTFE3BOHFVQQFS#PVOE3BOHFVQQFS#PVOE  ӈͷ୺఺ΛؚΉ͔൱͔  ൒։۠ؒͷΈۭ۠ؒΛද͢ࣄ͕Մೳ  ด۠ؒͷΈ#PVOEͷ࠷େ஋Λൣғ಺ʹؚΉ3BOHFΛఆٛՄೳ  DPOUBJOT *OUNBY
  13. Copyright © 2017 eureka, Inc. All rights reserved. 18 Swift.Range

    )BMG0QFO ൒։۠ؒ $MPTFE ด۠ؒ 6O$PVOUBCMF 3BOHF#PVOE $MPTFE3BOHF#PVOE $PVOUBCMF $PVOUBCMF3BOHF #PVOE $PVOUBCMF$MPTFE3BOHF #PVOE
  14. Copyright © 2017 eureka, Inc. All rights reserved. 19 Swift

    4 - PartialRange  ࠨӈ͍ͣΕ͔ͷ୺఺ #PVOE ͕ଘࡏ͠ͳ͍3BOHF let range1 = 0... // CountablePartialRangeFrom let range2 = 0.5... // PartialRangeFrom let range3 = ...100 // PartialRangeThrough let range4 = ..<100.0 // PartialRangeUpTo
  15. Copyright © 2017 eureka, Inc. All rights reserved. 20 Swift

    4 - PartialRange let target = 50 switch target { case 100...: print("greater than 100") case ..<100: print("less than 100") default: print(“default") } // > less than 100
  16. Copyright © 2017 eureka, Inc. All rights reserved. 21 NSRange

     MPDBUJPOͱMFOHUIΛ࣋ͭ  $PVOUBCMFͳ#PVOEͷΈ  /44USJOHͱ࿈ܞ  4XJGU4USJOHͱͷ૬ੑͷѱ͞͸ޙड़
  17. Copyright © 2017 eureka, Inc. All rights reserved. 24 slice

    String let array = ["❤", "#", "❤", "$", "%", "&"] let familyLove = array[1...2] // ["#", “❤"] let string = "あのイーハトーヴォのすきとおった風" let targetStart = string.index(string.startIndex, offsetBy: 2) let targetEnd = string.index(string.startIndex, offsetBy: 9) let substring2 = string[targetStart..<targetEnd] // ↓Swift 4からDeprecated //let substring = string.substring(with: targetStart..<targetEnd)
  18. Copyright © 2017 eureka, Inc. All rights reserved. 25 slice

    String let array = ["❤", "#", "❤", "$", "%", "&"] let familyLove = array[1…2] // ["#", “❤"] let string = "あのイーハトーヴォのすきとおった風" let targetStart = string.index(string.startIndex, offsetBy: 2) let targetEnd = string.index(string.startIndex, offsetBy: 9) let substring2 = string[targetStart..<targetEnd] // ↓Swift 4からDeprecated //let substring = string.substring(with: targetStart..<targetEnd)
  19. Copyright © 2017 eureka, Inc. All rights reserved. 26 slice

    with PartialRange string.substring(to: targetEnd) // Deprecated! string[..<targetEnd] string.substring(from: targetStart) // Deprecated! string[targetStart...]
  20. Copyright © 2017 eureka, Inc. All rights reserved. 27 slice

    with PartialRange string.substring(to: targetEnd) // Deprecated! string[..<targetEnd] string.substring(from: targetStart) // Deprecated! string[targetStart...]
  21. Copyright © 2017 eureka, Inc. All rights reserved. 29 why

    String.Index?  lߴίετͳॲཧͰ͋Δ͜ͱΛҙࣝͤ͞ɺ͔ͭޮ཰ͷྑ͍ཁૉΞΫηε͕Մ ೳͳ"1*ͱͳ͍ͬͯΔ͜ͱz  ʮ4XJGUͷ4USJOHͷ7JFXʹରͯ͠ɺ*OUͰTVCTDSJQUग़དྷͳ͍ཧ༝ʯ  !@NPOPTBO͔ΒҾ༻ *1 https://medium.com/swift-column/swift-string-7147f3f496b1
  22. Copyright © 2017 eureka, Inc. All rights reserved. 30 why

    String.Index?  /44USJOHʹ͓͚Δ65'Τϯίʔυ΍ɺ65'7JFXͳͲ֤छΤϯίʔυ 7JFXͱॻهૉΫϥελͷࠩҟΛҙࣝͤ͞Δ  *OUͰද͢*OEFYͱ֤छΤϯίʔυ͞Εͨจࣈྻʹ͓͚Δ*OEFY͕ඞͣ͠΋ Ұக͠ͳ͍ҝɺ4USJOH*OEFYͰந৅Խ͢Δ
  23. Copyright © 2017 eureka, Inc. All rights reserved. 33 Unicodeͷجૅ

    Character View let string = "résumé〜" string.utf8.count // 15 string.utf16.count // 9 string.unicodeScalars.count // 8 string.characters.count // 8 (string as NSString).length // 9
  24. Copyright © 2017 eureka, Inc. All rights reserved. 34 UTF8View

    r é s u m é 〜 72 c3 a9 73 75 6d c3 a9 e3 9c 80 f0 9f 84 98 for view in string.utf8 { print(String(view, radix: 16)) }
  25. Copyright © 2017 eureka, Inc. All rights reserved. 35 UTF16View

    r é s u m é 〜 72 e9 73 75 6d e9 301c d83d de04 for view in string.utf16 { print(String(view, radix: 16)) }
  26. Copyright © 2017 eureka, Inc. All rights reserved. 36 UnicodeScalarView

    r é s u m é 〜 72 e9 73 75 6d e9 301c 1f604 for view in string.unicodeScalars { print(String(view.value, radix: 16)) }
  27. Copyright © 2017 eureka, Inc. All rights reserved. 37 ʮ1จࣈʯͱ͸

     Ϣʔβ͕ೝࣝ͢Δʮจࣈʯ͸ɺ6OJDPEFͷίʔυϙΠϯτ͕ෳ਺૊Έ߹Θ ͤͯߏ੒͞ΕΔࣄ΋͋Δ  ίʔυϙΠϯτΛҰఆͷج४Ͱ·ͱΊΔϩδοΫ͕ڥքΞϧΰϦζϜ #PVOEBSJFT"MHPSJUIN   ڥքΞϧΰϦζϜʹΑͬͯϢʔβ͕Ұจࣈͱͯ͠ೝࣝ͢Δ͋ͭ·ΓΛఆٛ ͨ͠΋ͷ͕ॻهૉΫϥελ (SBQIFNF$MVTUFST
  28. Copyright © 2017 eureka, Inc. All rights reserved. 38 ֦ுॻهૉΫϥελ

     4USJOHDIBSBDUFST͸֦ுॻهૉΫϥελ &YUFOEFE(SBQIFNF $MVTUFST Λද͢  ॻهૉΫϥελͷڥքΞϧΰϦζϜ͸ෳࡶɺ׌ͭઢܗ૸ࠪΛߦ͏ҝɺίε τ͕ߴ͍
  29. Copyright © 2017 eureka, Inc. All rights reserved. 39 ֦ுॻهૉΫϥελ

    ڥքϧʔϧ 1. ςΩετ͕ۭͰͳ͍ݶΓɺςΩετͷઌ಄ͱ࠷ޙ͸ڥքʹͳΔ 2. CRͱLFͷؒ͸ڥքʹͳΒͳ͍ɻ΋͘͠͸ɺControlɺCRɺLFͷલޙΛڥքʹ͢Δ 3. ϋϯάϧͷԻઅγʔέϯε͕ଓ͘৔߹͸ڥքʹͳΒͳ͍ 4. ZWJ΍֦ுΩϟϥΫλͷલ͸ڥքʹͳΒͳ͍ 5. SpacingMarkͷલɺ΋͘͠͸ઌ಄௥Ճจࣈͷޙ͸ڥքʹͳΒͳ͍ 6. Emoji Modifier Sequenceɺ΋͘͠͸ZWJΛؚΉ৔߹͸ڥքʹͳΒͳ͍ 7. ࠃضֆจࣈΛؚΉ৔߹͸ڥքʹͳΒͳ͍ 8. ্هͷ৚݅ʹؚ·Εͳ͍৔߹ɺڥքʹͳΔ http://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries
  30. Copyright © 2017 eureka, Inc. All rights reserved. 40 ֦ுॻهૉΫϥελ

    ڥքϧʔϧ 1. ςΩετ͕ۭͰͳ͍ݶΓɺςΩετͷઌ಄ͱ࠷ޙ͸ڥքʹͳΔ 2. CRͱLFͷؒ͸ڥքʹͳΒͳ͍ɻ΋͘͠͸ɺControlɺCRɺLFͷલޙΛڥքʹ͢Δ 3. ϋϯάϧͷԻઅγʔέϯε͕ଓ͘৔߹͸ڥքʹͳΒͳ͍ 4. ZWJ΍֦ுΩϟϥΫλͷલ͸ڥքʹͳΒͳ͍ 5. SpacingMarkͷલɺ΋͘͠͸ઌ಄௥Ճจࣈͷޙ͸ڥքʹͳΒͳ͍ 6. Emoji Modifier Sequenceɺ΋͘͠͸ZWJΛؚΉ৔߹͸ڥքʹͳΒͳ͍ 7. ࠃضֆจࣈΛؚΉ৔߹͸ڥքʹͳΒͳ͍ 8. ্هͷ৚݅ʹؚ·Εͳ͍৔߹ɺڥքʹͳΔ http://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries ཁ͢ΔʹΊΜͲ͍ʂ
  31. Copyright © 2017 eureka, Inc. All rights reserved. 42 NSੈքʹ͓͚ΔString

    Range  /44USJOH͸65'  4USJOHͱ/44USJOHΛԣஅͯ͠3BOHFΛѻ͏৔߹͸65'Ͱ͋Δ͜ͱΛߟ ྀ͢Δ
  32. Copyright © 2017 eureka, Inc. All rights reserved. 43 NSString

    slice // 1文字目を取得する let string = "こんにちは!" let startIndex = string.startIndex let endIndex = string.index(startIndex, offsetBy: 1) string[startIndex..<endIndex] // "" let nsString = string as NSString nsString.substring(with: NSRange(location: 0, length: 1)) // “U+FFFD"
  33. Copyright © 2017 eureka, Inc. All rights reserved. 44 NSString

    substring // 1文字目を取得する let string = "こんにちは!" let startIndex = string.startIndex let endIndex = string.index(startIndex, offsetBy: 1) string[startIndex..<endIndex] // "" let nsString = string as NSString nsString.substring(with: NSRange(location: 0, length: 1)) // “U+FFFD”
  34. Copyright © 2017 eureka, Inc. All rights reserved. 45 String.Index

     65'ͷίʔυϙΠϯτͱͯ͠ʮʯ͸͕ͭͩɺ4USJOH*OEFY͸ॻهૉ ΫϥελΛߟྀ  ͓ͦΒ͘಺෦తʹ͸65'ͰFODPEF*OEFYΛ͍࣋ͬͯΔ  ந৅Խ͞Ε͍ͯΔҝɺ಺෦ͷ0⒎TFU͸ࠓޙҙຯ͕มΘΔՄೳੑ͕͋Δ let str = "" str.index(after: str.startIndex).encodedOffset == 2 // -> true
  35. Copyright © 2017 eureka, Inc. All rights reserved. 46 Swift

    3ʹ͓͚ΔSwift.Range to NSRange let utf16String = string.utf16 let utf16StartPoisition = startIndex.samePosition(in: utf16String) let utf16EndPoisition = endIndex.samePosition(in: utf16String) let distance = utf16StartPoisition.distance(to: utf16EndPoisition) let nsString = string as NSString nsString.substring(with: NSRange(location: 0, length: distance))
  36. Copyright © 2017 eureka, Inc. All rights reserved. 47 Swift

    3ʹ͓͚ΔSwift.Range > NSRange let utf16String = string.utf16 let utf16StartPoisition = startIndex.samePosition(in: utf16String) let utf16EndPoisition = endIndex.samePosition(in: utf16String) let distance = utf16StartPoisition.distance(to: utf16EndPoisition) let nsString = string as NSString nsString.substring(with: NSRange(location: 0, length: distance))
  37. Copyright © 2017 eureka, Inc. All rights reserved. 48 Swift

    3ʹ͓͚ΔSwift.Range > NSRange let utf16String = string.utf16 let utf16StartPoisition = startIndex.samePosition(in: utf16String) let utf16EndPoisition = endIndex.samePosition(in: utf16String) let distance = utf16StartPoisition.distance(to: utf16EndPoisition) let nsString = string as NSString nsString.substring(with: NSRange(location: 0, length: distance)) // ""
  38. Copyright © 2017 eureka, Inc. All rights reserved. 49 Swift

    4 let range = NSRange(startIndex..<endIndex, in: string) (string as NSString).substring(with: range) // ""  /43BOHF SFHJPO3BOHF&YQSFTTJPO JO4USJOH1SPUPDPM ͕௥Ճ
  39. Copyright © 2017 eureka, Inc. All rights reserved. 51 Swift

    4  4XJGUͰ6OJDPEFʹରԠ  4VC4USJOH5ZQFͷ௥Ճ
  40. Copyright © 2017 eureka, Inc. All rights reserved. 52 Swift

    4 - Unicode 9 ʹରԠ  4XJGUͷ৔߹ɺ6OJDPEFʹະରԠͰ͋Δҝɺจࣈ਺ͱDIBSBDUFSTͷ਺͕ ߹Θͳ͍৔߹͕͋Δ  4USJOHTMJDFʹ΋Өڹ "-".characters.count // 4 ".".characters.count // 3
  41. Copyright © 2017 eureka, Inc. All rights reserved. 53 Swift

    3ͷ৔߹ // 1文字目を取得 let emoji = “-家族" let startIndex = emoji.startIndex let endIndex = emoji.index(after: startIndex) emoji[startIndex..<endIndex]
  42. Copyright © 2017 eureka, Inc. All rights reserved. 54 Swift

    3ͷ৔߹ // 1文字目を取得 let emoji = “-家族" let startIndex = emoji.startIndex let endIndex = emoji.index(after: startIndex) emoji[startIndex..<endIndex] // -> ""
  43. Copyright © 2017 eureka, Inc. All rights reserved. 55 Swift

    3ͷ৔߹ // 1文字目を取得 let emoji = “-家族" let startIndex = emoji.startIndex let endIndex = emoji.index(after: startIndex) emoji[startIndex..<endIndex] // -> ""
  44. Copyright © 2017 eureka, Inc. All rights reserved. 56 Unicode

    - ZWJ 0 aV\%^  aV\%^  aV\%^  . aV\%^  aV\%^   ;8+ ;FSP8JEUI+PJOFS ʹΑͬͯ݁߹͞Εͨ৽͍͠ֆจࣈ  4XJGU͸;8+ʹରԠ͍ͯ͠ͳ͍ҝɺͦΕͧΕจࣈͱͯ͠ѻΘΕΔ
  45. Copyright © 2017 eureka, Inc. All rights reserved. 57 Swift

    4 supports Unicode 9 // 1文字目を取得 let emoji = “-家族" emoji.count // 3 let startIndex = emoji.startIndex let endIndex = emoji.index(after: startIndex) emoji[startIndex..<endIndex] // -> "-"
  46. Copyright © 2017 eureka, Inc. All rights reserved. 58 Swift

    4 supports Unicode 9 // 1文字目を取得 let emoji = “-家族" emoji.count // 3 let startIndex = emoji.startIndex let endIndex = emoji.index(after: startIndex) emoji[startIndex..<endIndex] // -> "-" NFFUT6
  47. Copyright © 2017 eureka, Inc. All rights reserved. 59 Swift

    4 SubString͕௥Ճ let string = "あのイーハトーヴォのすきとおった風" let targetStart = string.index(string.startIndex, offsetBy: 2) let targetEnd = string.index(string.startIndex, offsetBy: 9) let subString = string[targetStart..<targetEnd] subString.startIndex // 2 (Swift 3の場合、 startIndex == 0)
  48. Copyright © 2017 eureka, Inc. All rights reserved. 60 Swift

    4 - Substring  4XJGUͰ͸ɺ4USJOH͔ΒTMJDF͞Εͨจࣈྻ͸4USJOHͰ͸ͳ͘ɺ4VCTUSJOH 5ZQFͱͳΔ  จࣈྻεϥΠεͷύϑΥʔϚϯε޲্  ྆5ZQFڞ4USJOH1SPUPDPMΛ࣮૷͍ͯ͠Δҝɺ΄΅ಉ͡ڍಈ  TUBSU*OEFYɺFOE*OEFY͕ݩͷ4USJOHͷ*OEFYΛอ͍࣋ͯ͠Δҝɺ஫ҙ͕ඞ ཁ
  49. Copyright © 2017 eureka, Inc. All rights reserved. 61 Substring

    to String let subString = string[targetStart..<targetEnd] subString.startIndex // 2 // initializerを使う String(subString).startIndex // 0
  50. Copyright © 2017 eureka, Inc. All rights reserved. 62 ·ͱΊ

     4XJGUͷ3BOHF͸͍͔ͭ͘ଘࡏ͢Δ͕ɺ֤3BOHFͷಛ௃Λཧղ  /4ͷੈքͱ4XJGUͷੈքɺͦΕͧΕͷ3BOHFΛଚॏ͠Α͏  4USJOHʹ͓͚Δ3BOHF͸ɺ4XJGUͱ4XJGUͷࠩҟʹ஫ҙ͠Α͏  ॻهૉΫϥελ΁ѪΛ͜Ίͯ