2017-02-08 1 views
6

NSAttributedString을 사용하여 API에서 오는 텍스트의 일부를 채색합니다 (Twitter에서 "@mention"이라고 생각하십시오).NSAttributedString 및 emojis : 위치 및 길이 문제가 발생했습니다.

API는 나에게 색칠해야하는 멘션 (또는 링크, 태그 등) 인 텍스트의 부분을 나타내는 엔티티의 텍스트와 배열을 제공합니다.

하지만 때때로 이모티콘으로 인해 채색이 상쇄됩니다. 이 텍스트 예를 들어


, ". 일부 텍스트를 @ericd @apero"

API는 제공합니다

[ { " 텍스트 ":"ericd ", "len ": 6, "pos ": 0 }, { "텍스트": "apero" "렌": 6, "POS"18 } ]

내가 성공적으로 NSAttributedString은로 번역 NSRange 사용 :

for m in entities.mentions { 
    let r = NSMakeRange(m.pos, m.len) 
    myAttributedString.addAttribute(NSForegroundColorAttributeName, value: someValue, range: r) 
} 

"pos": 18이 정확하다는 것을 알 수 있습니다. "@apero"가 시작됩니다. 색이 지정된 부분은 "@ericd"및 "@apero"입니다.

하지만 이모티콘의 일부 특정 조합이 텍스트에 사용되는 경우, API가 NSAttributedString은 잘 번역하지 않고는, 착색이 오프셋 :

는 "일부 텍스트를 @ericd ✌ @apero."

준다 :

[ { "텍스트": "ericd" "LEN"6 "POS"0 } { "텍스트": "apero" "LEN"6 "POS"22 } ]

"pos": 22 : API 작성자는 이것이 올바른 것으로 말하고 그 견해를 이해합니다.

불행히도, NSAttributedString은 동의하지 않는, 내 착색이 꺼져 다음 "POS"이 때문에 이모티콘의 너무 짧은 때문에

enter image description here

두 번째 언급에 대한 마지막 문자

가 (컬러되지 않습니다 ?).

이미 짐작 하셨겠지만 API가 작동하는 방식을 변경할 수는 없으므로 클라이언트 측에서 수정해야합니다.

제외하고 ... 나는 무엇을해야할지 몰라. 어떤 그림 이모티콘이 텍스트에 있는지 감지하고 문제가있는 그림이있는 경우 멘션의 위치를 ​​수동으로 수정해야합니까? 그러나 어떤 이모티콘이 위치를 이동시키는 지 감지하는 기준은 무엇입니까? 그리고 얼마나 많은 상쇄가 필요한지 결정하는 방법? 어쩌면 문제가 NSAttributedString에 의해 발생합니까?

나는 이것이 이모티스 길이와 관련이 있다고 생각합니다. 길이가 개별 문자로 비교되었지만 ... 음 ... 나는 잃어버린 (한숨). 내 API이 하나와 호환이기 때문에 this stuff 유사한 솔루션을 구현하기 위해 노력했지만, 그것은 부분적으로 만 작동


참고 일부 이모티콘은 여전히 ​​인덱스를 파괴했다 :

enter image description here

답변

9

스위프트 String은 내용에 다른 "보기"를 제공합니다. 좋은 개요는 스위프트 블로그 "Strings in Swift 2" 주어진다 :

  • characters 문자 값 또는 확장 된 자모 클러스터의 집합이다.
  • unicodeScalars은 유니 코드 스칼라 값의 모음입니다.
  • utf8은 UTF-8 코드 단위의 모음입니다.
  • utf16은 UTF-16 코드 단위의 모음입니다. 당신의 API 에서이 토론에서 보니

, poslen는 유니 코드 스칼라 뷰의 인덱스입니다. 한편

NSMutableAttributedString addAttribute()의 방법, 즉 NSString에서 UTF-16 코드 포인트의 인덱스에 대응 범위 NSRange 걸린다.

String

가 다른 관점의 지표 사이에 "번역"하는 방법을 제공합니다 ( NSRange to Range<String.Index> 비교) :

let text = "@ericd Some text. ✌ @apero" 
let pos = 22 
let len = 6 

// Compute String.UnicodeScalarView indices for first and last position: 
let from32 = text.unicodeScalars.index(text.unicodeScalars.startIndex, offsetBy: pos) 
let to32 = text.unicodeScalars.index(from32, offsetBy: len) 

// Convert to String.UTF16View indices: 
let from16 = from32.samePosition(in: text.utf16) 
let to16 = to32.samePosition(in: text.utf16) 

// Convert to NSRange by computing the integer distances: 
let nsRange = NSRange(location: text.utf16.distance(from: text.utf16.startIndex, to: from16), 
         length: text.utf16.distance(from: from16, to: to16)) 

을이 NSRange 당신이 기인 문자열에 필요한 것입니다 :

let attrString = NSMutableAttributedString(string: text) 
attrString.addAttribute(NSForegroundColorAttributeName, 
         value: UIColor.red, 
         range: nsRange) 

Swift 4 (Xcode 9) 업데이트 : S wift 4는 표준 라이브러리 는 스위프트 사이 String 범위 및 NSString 범위를 변환하는 방법을 제공하므로 계산

let text = "@ericd Some text. ✌ @apero" 
let pos = 22 
let len = 6 

// Compute String.UnicodeScalarView indices for first and last position: 
let fromIdx = text.unicodeScalars.index(text.unicodeScalars.startIndex, offsetBy: pos) 
let toIdx = text.unicodeScalars.index(fromIdx, offsetBy: len) 

// Compute corresponding NSRange: 
let nsRange = NSRange(fromIdx..<toIdx, in: text) 
+1

흥미를 단순화! (내가 사용하고있는 범위는 이미 Swift Range가 아닌 NSRange 다.) 이것을 공부하고 테스트를 실행하려면 시간이 필요합니다. API 호출과 비교하여 어떻게 동작하는지 확인하십시오.감사합니다. 가능한 경우 피드백을 드리겠습니다. – Moritz

+0

예에서 pos 22와 len 6을 사용하면이 텍스트에 대해 내 API가 반환됩니다. "@apero"는 전체 설명 대신 "@"[https://www.evernote.com/l/AOznB6IhPzxJrbvva5Jxx24cyFv9MrhSqkI). – Moritz

+0

@EricAya : 그러나 "@apero"의 "@"는 22가 아니라 21 위입니다. 문자를 어떻게 계산합니까? –

관련 문제