Sur*_*gch 51 string unicode ios swift mongolian-vertical-script
如果您对Mongolian的细节不感兴趣,但只想快速回答有关在Swift中使用和转换Unicode值的问题,请跳到接受答案的第一部分.
我想渲染传统蒙古语的 Unicode文本,以便在iOS应用程序中使用.更好和长期的解决方案是使用AAT智能字体来渲染这个复杂的脚本.(这些字体确实存在,但它们的许可证不允许修改和非个人使用.)但是,由于我从未制作过字体,更不用说AAT字体的所有渲染逻辑了,我只是打算自己进行渲染.斯威夫特现在.也许在以后我可以学习制作智能字体.
在外部我将使用Unicode文本,但在内部(在a中显示UITextView
)我将Unicode转换为以哑字体存储的单个字形(用Unicode PUA值编码).所以我的渲染引擎需要将蒙古语Unicode值(范围:U + 1820到U + 1842)转换为存储在PUA中的字形值(范围:U + E360到U + E5CF).无论如何,这是我的计划,因为它是我过去在Java中所做的,但也许我需要改变我的整个思维方式.
下图显示su在蒙古语中使用两种不同形式的字母u(红色)两次写入.(蒙古文是垂直书写的,字母连接像英文草书一样.)
在Unicode中,这两个字符串将表示为
var suForm1: String = "\u{1830}\u{1826}"
var suForm2: String = "\u{1830}\u{1826}\u{180B}"
Run Code Online (Sandbox Code Playgroud)
自由变量选择器(U + 180B)in suForm2
被Swift识别(正确)String
为与其前面的u(U + 1826)的单位.Swift认为它是一个单一的字符,一个扩展的字形集群.但是,为了自己进行渲染,我需要将u(U + 1826)和FVS1(U + 180B)区分为两个不同的UTF-16代码点.
出于内部显示的目的,我将上述Unicode字符串转换为以下呈现的字形字符串:
suForm1 = "\u{E46F}\u{E3BA}"
suForm2 = "\u{E46F}\u{E3BB}"
Run Code Online (Sandbox Code Playgroud)
我一直在玩Swift String
和Character
.关于它们有很多方便的东西,但是因为在我的特殊情况下我只使用UTF-16代码单元,我想知道我是否应该使用旧的NSString
而不是Swift的String
.我意识到我可以String.utf16
用来获得UTF-16代码点,但转换回来String
并不是很好.
它会更好坚持String
和Character
或者我应该使用NSString
和unichar
?
已隐藏此问题的更新以清理页面.查看编辑历史记录.
Sur*_*gch 62
针对Swift 3进行了更新
对于几乎每个人都在谁访问了这个问题,未来String
,并Character
会为你的答案.
直接在代码中设置Unicode值:
var str: String = "I want to visit ??, ??????, ?????, ???????, and ???. "
var character: Character = ""
Run Code Online (Sandbox Code Playgroud)
使用十六进制设置值
var str: String = "\u{61}\u{5927}\u{1F34E}\u{3C0}" // a??
var character: Character = "\u{65}\u{301}" // é = "e" + accent mark
Run Code Online (Sandbox Code Playgroud)
请注意,Swift Character可以由多个Unicode代码点组成,但看起来是单个字符.这称为扩展字形集群.
也看到这个问题.
转换为Unicode值:
str.utf8
str.utf16
str.unicodeScalars // UTF-32
String(character).utf8
String(character).utf16
String(character).unicodeScalars
Run Code Online (Sandbox Code Playgroud)
从Unicode十六进制值转换:
let hexValue: UInt32 = 0x1F34E
// convert hex value to UnicodeScalar
guard let scalarValue = UnicodeScalar(hexValue) else {
// early exit if hex does not form a valid unicode value
return
}
// convert UnicodeScalar to String
let myString = String(scalarValue) //
Run Code Online (Sandbox Code Playgroud)
或者:
let hexValue: UInt32 = 0x1F34E
if let scalarValue = UnicodeScalar(hexValue) {
let myString = String(scalarValue)
}
Run Code Online (Sandbox Code Playgroud)
还有一些例子
let value0: UInt8 = 0x61
let value1: UInt16 = 0x5927
let value2: UInt32 = 0x1F34E
let string0 = String(UnicodeScalar(value0)) // a
let string1 = String(UnicodeScalar(value1)) // ?
let string2 = String(UnicodeScalar(value2)) //
// convert hex array to String
let myHexArray = [0x43, 0x61, 0x74, 0x203C, 0x1F431] // an Int array
var myString = ""
for hexValue in myHexArray {
myString.append(UnicodeScalar(hexValue))
}
print(myString) // Cat?
Run Code Online (Sandbox Code Playgroud)
请注意,对于UTF-8和UTF-16,转换并不总是那么容易.(参见UTF-8,UTF-16和UTF-32问题.)
也可以一起工作NSString
,并unichar
在斯威夫特,但你应该明白,除非你熟悉目标C和擅长的语法转换成斯威夫特,这将是很难找到良好的文档.
此外,unichar
是一个UInt16
数组,如上所述,转换UInt16
为Unicode标量值并不总是容易的(即,转换代理对,如表情符号和上层代码平面中的其他字符).
由于问题中提到的原因,我最终没有使用上述任何方法.相反,我编写了自己的字符串结构,它基本上是一个UInt32
用于保存Unicode标量值的数组.
同样,这不是大多数人的解决方案.如果您只需要扩展或稍微扩展功能,首先考虑使用扩展.String
Character
但是,如果您确实需要专门使用Unicode标量值,则可以编写自定义结构.
优点是:
String
,Character
,UnicodeScalar
,UInt32
,等)做字符串操作的时候.String
很容易.不利条件是:
你可以自己做,但这是我的参考.最困难的部分是使它成为Hashable.
// This struct is an array of UInt32 to hold Unicode scalar values
// Version 3.4.0 (Swift 3 update)
struct ScalarString: Sequence, Hashable, CustomStringConvertible {
fileprivate var scalarArray: [UInt32] = []
init() {
// does anything need to go here?
}
init(_ character: UInt32) {
self.scalarArray.append(character)
}
init(_ charArray: [UInt32]) {
for c in charArray {
self.scalarArray.append(c)
}
}
init(_ string: String) {
for s in string.unicodeScalars {
self.scalarArray.append(s.value)
}
}
// Generator in order to conform to SequenceType protocol
// (to allow users to iterate as in `for myScalarValue in myScalarString` { ... })
func makeIterator() -> AnyIterator<UInt32> {
return AnyIterator(scalarArray.makeIterator())
}
// append
mutating func append(_ scalar: UInt32) {
self.scalarArray.append(scalar)
}
mutating func append(_ scalarString: ScalarString) {
for scalar in scalarString {
self.scalarArray.append(scalar)
}
}
mutating func append(_ string: String) {
for s in string.unicodeScalars {
self.scalarArray.append(s.value)
}
}
// charAt
func charAt(_ index: Int) -> UInt32 {
return self.scalarArray[index]
}
// clear
mutating func clear() {
self.scalarArray.removeAll(keepingCapacity: true)
}
// contains
func contains(_ character: UInt32) -> Bool {
for scalar in self.scalarArray {
if scalar == character {
return true
}
}
return false
}
// description (to implement Printable protocol)
var description: String {
return self.toString()
}
// endsWith
func endsWith() -> UInt32? {
return self.scalarArray.last
}
// indexOf
// returns first index of scalar string match
func indexOf(_ string: ScalarString) -> Int? {
if scalarArray.count < string.length {
return nil
}
for i in 0...(scalarArray.count - string.length) {
for j in 0..<string.length {
if string.charAt(j) != scalarArray[i + j] {
break // substring mismatch
}
if j == string.length - 1 {
return i
}
}
}
return nil
}
// insert
mutating func insert(_ scalar: UInt32, atIndex index: Int) {
self.scalarArray.insert(scalar, at: index)
}
mutating func insert(_ string: ScalarString, atIndex index: Int) {
var newIndex = index
for scalar in string {
self.scalarArray.insert(scalar, at: newIndex)
newIndex += 1
}
}
mutating func insert(_ string: String, atIndex index: Int) {
var newIndex = index
for scalar in string.unicodeScalars {
self.scalarArray.insert(scalar.value, at: newIndex)
newIndex += 1
}
}
// isEmpty
var isEmpty: Bool {
return self.scalarArray.count == 0
}
// hashValue (to implement Hashable protocol)
var hashValue: Int {
// DJB Hash Function
return self.scalarArray.reduce(5381) {
($0 << 5) &+ $0 &+ Int($1)
}
}
// length
var length: Int {
return self.scalarArray.count
}
// remove character
mutating func removeCharAt(_ index: Int) {
self.scalarArray.remove(at: index)
}
func removingAllInstancesOfChar(_ character: UInt32) -> ScalarString {
var returnString = ScalarString()
for scalar in self.scalarArray {
if scalar != character {
returnString.append(scalar)
}
}
return returnString
}
func removeRange(_ range: CountableRange<Int>) -> ScalarString? {
if range.lowerBound < 0 || range.upperBound > scalarArray.count {
return nil
}
var returnString = ScalarString()
for i in 0..<scalarArray.count {
if i < range.lowerBound || i >= range.upperBound {
returnString.append(scalarArray[i])
}
}
return returnString
}
// replace
func replace(_ character: UInt32, withChar replacementChar: UInt32) -> ScalarString {
var returnString = ScalarString()
for scalar in self.scalarArray {
if scalar == character {
returnString.append(replacementChar)
} else {
returnString.append(scalar)
}
}
return returnString
}
func replace(_ character: UInt32, withString replacementString: String) -> ScalarString {
var returnString = ScalarString()
for scalar in self.scalarArray {
if scalar == character {
returnString.append(replacementString)
} else {
returnString.append(scalar)
}
}
return returnString
}
func replaceRange(_ range: CountableRange<Int>, withString replacementString: ScalarString) -> ScalarString {
var returnString = ScalarString()
for i in 0..<scalarArray.count {
if i < range.lowerBound || i >= range.upperBound {
returnString.append(scalarArray[i])
} else if i == range.lowerBound {
returnString.append(replacementString)
}
}
return returnString
}
// set (an alternative to myScalarString = "some string")
mutating func set(_ string: String) {
self.scalarArray.removeAll(keepingCapacity: false)
for s in string.unicodeScalars {
self.scalarArray.append(s.value)
}
}
// split
func split(atChar splitChar: UInt32) -> [ScalarString] {
var partsArray: [ScalarString] = []
if self.scalarArray.count == 0 {
return partsArray
}
var part: ScalarString = ScalarString()
for scalar in self.scalarArray {
if scalar == splitChar {
partsArray.append(part)
part = ScalarString()
} else {
part.append(scalar)
}
}
partsArray.append(part)
return partsArray
}
// startsWith
func startsWith() -> UInt32? {
return self.scalarArray.first
}
// substring
func substring(_ startIndex: Int) -> ScalarString {
// from startIndex to end of string
var subArray: ScalarString = ScalarString()
for i in startIndex..<self.length {
subArray.append(self.scalarArray[i])
}
return subArray
}
func substring(_ startIndex: Int, _ endIndex: Int) -> ScalarString {
// (startIndex is inclusive, endIndex is exclusive)
var subArray: ScalarString = ScalarString()
for i in startIndex..<endIndex {
subArray.append(self.scalarArray[i])
}
return subArray
}
// toString
func toString() -> String {
var string: String = ""
for scalar in self.scalarArray {
if let validScalor = UnicodeScalar(scalar) {
string.append(Character(validScalor))
}
}
return string
}
// trim
// removes leading and trailing whitespace (space, tab, newline)
func trim() -> ScalarString {
//var returnString = ScalarString()
let space: UInt32 = 0x00000020
let tab: UInt32 = 0x00000009
let newline: UInt32 = 0x0000000A
var startIndex = self.scalarArray.count
var endIndex = 0
// leading whitespace
for i in 0..<self.scalarArray.count {
if self.scalarArray[i] != space &&
self.scalarArray[i] != tab &&
self.scalarArray[i] != newline {
startIndex = i
break
}
}
// trailing whitespace
for i in stride(from: (self.scalarArray.count - 1), through: 0, by: -1) {
if self.scalarArray[i] != space &&
self.scalarArray[i] != tab &&
self.scalarArray[i] != newline {
endIndex = i + 1
break
}
}
if endIndex <= startIndex {
return ScalarString()
}
return self.substring(startIndex, endIndex)
}
// values
func values() -> [UInt32] {
return self.scalarArray
}
}
func ==(left: ScalarString, right: ScalarString) -> Bool {
return left.scalarArray == right.scalarArray
}
func +(left: ScalarString, right: ScalarString) -> ScalarString {
var returnString = ScalarString()
for scalar in left.values() {
returnString.append(scalar)
}
for scalar in right.values() {
returnString.append(scalar)
}
return returnString
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
35525 次 |
最近记录: |