// 空文字をルビとして設定する
let ruby = ""
var textRef: [Unmanaged<CFString>?] = [Unmanaged<CFString>.passRetained(ruby as CFString) as Unmanaged<CFString>, .none, .none, .none]
let annotation = CTRubyAnnotationCreate(.auto, .auto, 0.5, &textRef[0]!)
let attributedString = NSAttributedString(
string: "漢字",
attributes: [kCTRubyAnnotationAttributeName as String: annotation]
// ↓ ここでEXC_BAD_ACCESSが発生する
let line = CTLineCreateWithAttributedString(attributedString)
ほかにも
let framesetter = CTFramesetterCreateWithAttributedString( attributedText)
// ↓ ここでEXC_BAD_ACCESSが発生する
let frame = CTFramesetterCreateFrame(framesetter, CFRange(), path, nil)
let text = "てめえらの|血《ち》は|何色《なにいろ》だーっ!!"
let parser = AozoraRubyParser(text: text)
if let result = parser.parse() {
for r in result {
print("\(r.text) \( (r.ruby != nil) ? "[" + r.ruby! + "]" : "" )")
}
}
こんな感じで出力されます
てめえらの
血 [ち]
は
何色 [なにいろ]
だーっ!!
class AozoraRubyParser {
class Result {
let text:String
let ruby:String?
init(text:String,ruby:String?) {
self.text = text
self.ruby = ruby
}
}
let text:String;
init(text:String) {
self.text = text;
}
func parse() -> [Result]?{
var result:[Result] = []
do {
var position = 0;
let nsText = text as NSString
let totalLength = nsText.length
let re = try NSRegularExpression(pattern: "|(.+?)《(.+?)》", options: [])
let matches = re.matches(in: text, options: [], range: NSRange(location: 0, length: totalLength))
for match in matches {
let matchRange = match.range;
// 現在の位置からrangeの先頭が離れていたら、その間の文字を抽出する
if position < matchRange.location {
let subRange = NSRange(location: position, length: matchRange.location - position)
result.append(Result(text: nsText.substring(with:subRange), ruby: nil))
}
position = matchRange.location + matchRange.length;
// 文字と読み仮名を抽出
let str = nsText.substring(with: match.rangeAt(1))
let ruby = nsText.substring(with: match.rangeAt(2))
result.append(Result(text: str, ruby: ruby))
}
// 文末の残りを追加
if totalLength > position {
let subRange = NSRange(location: position, length: totalLength - position)
result.append(Result(text: nsText.substring(with:subRange), ruby: nil))
}
}catch let err {
log.error("\(err)")
return nil;
}
return result
}
}