UITextViewの文字位置関連のAPI(positionとか、offsetとか、characterRangeとか)はNSString相当の位置で操作するので、Swiftの文字列(String)とは位置がずれてしまうようです。
NSStringはUTF16の配列として長さや位置を管理していますが、SwiftのStringは正確に文字数をカウントしているため、UTF16のサロゲート文字(16ビットで表現できない文字)が含まれると、NSStringとStringで位置ずれが発生します。
面倒ですが、Stringのutf16viewを使って地道に変換してやるしかなさそうです。SwiftのString.Index周りは文字数の正確さと実行速度の両立が必要なせいか、結構面倒な作りなので、下記のような拡張を作成しました。