回答編集履歴

1

修正

2017/01/15 05:48

投稿

_Kentarou
_Kentarou

スコア8490

test CHANGED
@@ -3,3 +3,227 @@
3
3
 
4
4
 
5
5
  [ルビを振る](http://qiita.com/woxtu/items/284369fd2654edac2248)
6
+
7
+
8
+
9
+ `Swift3`で動かしてみました。
10
+
11
+
12
+
13
+ ```swift
14
+
15
+ import UIKit
16
+
17
+
18
+
19
+ extension String {
20
+
21
+ func find(pattern: String) -> NSTextCheckingResult? {
22
+
23
+ do {
24
+
25
+ let re = try NSRegularExpression(pattern: pattern, options: [])
26
+
27
+ return re.firstMatch(
28
+
29
+ in: self,
30
+
31
+ options: [],
32
+
33
+ range: NSMakeRange(0, self.utf16.count))
34
+
35
+ } catch {
36
+
37
+ return nil
38
+
39
+ }
40
+
41
+ }
42
+
43
+
44
+
45
+ func replace(pattern: String, template: String) -> String {
46
+
47
+ do {
48
+
49
+ let re = try NSRegularExpression(pattern: pattern, options: [])
50
+
51
+ return re.stringByReplacingMatches(
52
+
53
+ in: self,
54
+
55
+ options: [],
56
+
57
+ range: NSMakeRange(0, self.utf16.count),
58
+
59
+ withTemplate: template)
60
+
61
+ } catch {
62
+
63
+ return self
64
+
65
+ }
66
+
67
+ }
68
+
69
+ }
70
+
71
+
72
+
73
+ class View: UIView {
74
+
75
+
76
+
77
+ override func draw(_ rect: CGRect) {
78
+
79
+ let text = [
80
+
81
+ "「まさか、|後罪《クライム》の|触媒《カタリスト》を〈|讃来歌《オラトリオ》〉無しで?」",
82
+
83
+ "教師たちの狼狽した声が次々と上がる。",
84
+
85
+ "……なんでだろう。何を驚いているんだろう。",
86
+
87
+ "ただ普通に、この|触媒《カタリスト》を使って|名詠門《チャネル》を開かせただけなのに。",
88
+
89
+ "そう言えば、何を|詠《よ》ぼう。",
90
+
91
+ "自分の一番好きな花でいいかな。",
92
+
93
+ "どんな宝石より素敵な、わたしの大好きな緋色の花。",
94
+
95
+ "――『|Keinez《赤》』――",
96
+
97
+ "そして、少女の口ずさんだその後に――",
98
+
99
+ ]
100
+
101
+ .joined(separator: "\n")
102
+
103
+
104
+
105
+ let attributed =
106
+
107
+ text
108
+
109
+ .replace(pattern: "(|.+?《.+?》)", template: ",$1,")
110
+
111
+ .components(separatedBy: ",")
112
+
113
+ .map { x -> NSAttributedString in
114
+
115
+ if let pair = x.find(pattern: "|(.+?)《(.+?)》") {
116
+
117
+ let string = (x as NSString).substring(with: pair.rangeAt(1))
118
+
119
+ let ruby = (x as NSString).substring(with: pair.rangeAt(2))
120
+
121
+
122
+
123
+ var text: [Unmanaged<CFString>?] = [Unmanaged<CFString>.passRetained(ruby as CFString) as Unmanaged<CFString>, .none, .none, .none]
124
+
125
+
126
+
127
+ let annotation = CTRubyAnnotationCreate(.auto, .auto, 0.5, &text[0]!)
128
+
129
+
130
+
131
+ return NSAttributedString(
132
+
133
+ string: string,
134
+
135
+ attributes: [kCTRubyAnnotationAttributeName as String: annotation])
136
+
137
+ } else {
138
+
139
+ return NSAttributedString(string: x, attributes: nil)
140
+
141
+ }
142
+
143
+ }
144
+
145
+ .reduce(NSMutableAttributedString()) { $0.append($1); return $0 }
146
+
147
+
148
+
149
+ var height = 28.0
150
+
151
+ let settings = [
152
+
153
+ CTParagraphStyleSetting(
154
+
155
+ spec: .minimumLineHeight,
156
+
157
+ valueSize: Int(MemoryLayout.size(ofValue: height)),
158
+
159
+ value: &height)
160
+
161
+ ]
162
+
163
+ let style = CTParagraphStyleCreate(settings, Int(settings.count))
164
+
165
+
166
+
167
+ attributed.addAttributes([
168
+
169
+ NSFontAttributeName: UIFont(name: "HiraMinProN-W3", size: 14.0)!,
170
+
171
+ NSVerticalGlyphFormAttributeName: true,
172
+
173
+ kCTParagraphStyleAttributeName as String: style,
174
+
175
+ ],
176
+
177
+ range: NSMakeRange(0, attributed.length))
178
+
179
+
180
+
181
+ let context = UIGraphicsGetCurrentContext()
182
+
183
+
184
+
185
+ context!.setFillColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
186
+
187
+ context!.addRect(rect)
188
+
189
+ context?.fillPath()
190
+
191
+
192
+
193
+ context!.rotate(by: CGFloat(M_PI_2))
194
+
195
+ context!.translateBy(x: 30.0, y: 35.0)
196
+
197
+ context!.scaleBy(x: 1.0, y: -1.0)
198
+
199
+
200
+
201
+ let framesetter = CTFramesetterCreateWithAttributedString(attributed)
202
+
203
+ let path = CGPath(rect: CGRect(x: 0.0, y: 0.0, width: rect.height, height: rect.width), transform: nil)
204
+
205
+ let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, nil)
206
+
207
+ CTFrameDraw(frame, context!)
208
+
209
+ }
210
+
211
+ }
212
+
213
+
214
+
215
+ class ViewController: UIViewController {
216
+
217
+ override func loadView() {
218
+
219
+ super.loadView()
220
+
221
+
222
+
223
+ self.view = View()
224
+
225
+ }
226
+
227
+ }
228
+
229
+ ```