Automatically align text in UILabel according to t

2019-03-14 01:49发布

I'm interested in setting some text into a UILabel, and depending on the directionality of the language (e.g., Hebrew - right-to-left [RTL], English - left-to-right [LTR]) set the alignment of the UILabel.

Note that using iOS 6's NSTextAlignmentNatural does not solve the problem, as it chooses alignment according to the current locale, experiments show.

4条回答
贪生不怕死
2楼-- · 2019-03-14 02:28

In HTML5 this can be done by applying dir="auto" to the element. It's implemented in WebKit, though I'm not completely sure that it's available in iOS.

dir="auto" is very simple, and you can probably implement it yourself - just search for the first character that has strong directionality, and apply its directionality to the whole thing.

If you can't find anything in iOS, you can try to take some smarter ideas from the way StatusNet implemented it: http://status.net/sites/default/files/issues/1346_jquery.directionDetector.js

查看更多
smile是对你的礼貌
3楼-- · 2019-03-14 02:35

There is a solution that is based on the language detection of the string.

Method returns NSTextAlignmentNatural if direction can not be identified.

@implementation NSString (StringAlignmentDetection)

- (NSTextAlignment)naturalTextAligment
{
    NSArray *tagschemes = [NSArray arrayWithObjects:NSLinguisticTagSchemeLanguage, nil];
    NSLinguisticTagger *tagger = [[NSLinguisticTagger alloc] initWithTagSchemes:tagschemes options:0];
    [tagger setString:self];
    NSString *language = [tagger tagAtIndex:0 scheme:NSLinguisticTagSchemeLanguage tokenRange:NULL sentenceRange:NULL];

    NSTextAlignment alignment = NSTextAlignmentNatural;

    if(!language)
    {
        return alignment;
    }

    NSLocaleLanguageDirection direction = [NSLocale characterDirectionForLanguage: language];

    switch (direction)
    {
        case NSLocaleLanguageDirectionLeftToRight:
            alignment = NSTextAlignmentLeft;
            break;

        case NSLocaleLanguageDirectionRightToLeft:
            alignment = NSTextAlignmentRight;
            break;

        default:
            alignment = NSTextAlignmentNatural;
            break;
    }

    return alignment;
}

@end
查看更多
仙女界的扛把子
4楼-- · 2019-03-14 02:37

Ended up following the advice given in this SO answer: write a short script that will parse the Unicode data publicly available here, and generate code to identify whether a code-point has a strong R or AL directionality attribute. Then, the string is searched for the first such character. This is exactly what ubidi_getBaseDirection from the ICU package does.

Since the internal representation of NSString is UTF16 (which is a variable-length encoding), it is first converted to UTF32 in order to simplify the scanning code. An alternative approach would be to decode the string on the fly, which requires dealing with BOM and Unicode surrogates. Yet another approach is simply ignoring characters not representable by one unichar. For more details, see Wikipedia's UTF16 article.

Short Answer

@interface NSString (TextDirectionality)

/* Return 1 if the string is strongly LTR, -1 if strongly RTL, or 0 if neutral. */
/* See http://icu-project.org/apiref/icu4c/ubidi_8h.html#aeb1fd15743833278cc11906cd5a48aef */
-(int)getBaseDirection;

@end

@implementation NSString (TextDirectionality)

// Function takes UTF32 character, and not a unichar (=UTF16 character),
// because some Unicode characters need full 32 bits to represent.
BOOL isCodePointStrongRTL(UTF32Char c) {
  return ((c == 0x5BE) || (c == 0x5C0) || (c == 0x5C3) || (c == 0x5C6) || (c >= 0x5D0 && c <= 0x5EA) || (c >= 0x5F0 && c <= 0x5F4) || (c == 0x608) || (c == 0x60B) || (c == 0x60D) || (c == 0x61B) || (c >= 0x61E && c <= 0x64A) || (c >= 0x66D && c <= 0x66F) || (c >= 0x671 && c <= 0x6D5) || (c >= 0x6E5 && c <= 0x6E6) || (c >= 0x6EE && c <= 0x6EF) || (c >= 0x6FA && c <= 0x70D) || (c >= 0x70F && c <= 0x710) || (c >= 0x712 && c <= 0x72F) || (c >= 0x74D && c <= 0x7A5) || (c == 0x7B1) || (c >= 0x7C0 && c <= 0x7EA) || (c >= 0x7F4 && c <= 0x7F5) || (c == 0x7FA) || (c >= 0x800 && c <= 0x815) || (c == 0x81A) || (c == 0x824) || (c == 0x828) || (c >= 0x830 && c <= 0x83E) || (c >= 0x840 && c <= 0x858) || (c == 0x85E) || (c == 0x8A0) || (c >= 0x8A2 && c <= 0x8AC) || (c == 0x200F) || (c == 0xFB1D) || (c >= 0xFB1F && c <= 0xFB28) || (c >= 0xFB2A && c <= 0xFB36) || (c >= 0xFB38 && c <= 0xFB3C) || (c == 0xFB3E) || (c >= 0xFB40 && c <= 0xFB41) || (c >= 0xFB43 && c <= 0xFB44) || (c >= 0xFB46 && c <= 0xFBC1) || (c >= 0xFBD3 && c <= 0xFD3D) || (c >= 0xFD50 && c <= 0xFD8F) || (c >= 0xFD92 && c <= 0xFDC7) || (c >= 0xFDF0 && c <= 0xFDFC) || (c >= 0xFE70 && c <= 0xFE74) || (c >= 0xFE76 && c <= 0xFEFC) || (c >= 0x10800 && c <= 0x10805) || (c == 0x10808) || (c >= 0x1080A && c <= 0x10835) || (c >= 0x10837 && c <= 0x10838) || (c == 0x1083C) || (c >= 0x1083F && c <= 0x10855) || (c >= 0x10857 && c <= 0x1085F) || (c >= 0x10900 && c <= 0x1091B) || (c >= 0x10920 && c <= 0x10939) || (c == 0x1093F) || (c >= 0x10980 && c <= 0x109B7) || (c >= 0x109BE && c <= 0x109BF) || (c == 0x10A00) || (c >= 0x10A10 && c <= 0x10A13) || (c >= 0x10A15 && c <= 0x10A17) || (c >= 0x10A19 && c <= 0x10A33) || (c >= 0x10A40 && c <= 0x10A47) || (c >= 0x10A50 && c <= 0x10A58) || (c >= 0x10A60 && c <= 0x10A7F) || (c >= 0x10B00 && c <= 0x10B35) || (c >= 0x10B40 && c <= 0x10B55) || (c >= 0x10B58 && c <= 0x10B72) || (c >= 0x10B78 && c <= 0x10B7F) || (c >= 0x10C00 && c <= 0x10C48) || (c >= 0x1EE00 && c <= 0x1EE03) || (c >= 0x1EE05 && c <= 0x1EE1F) || (c >= 0x1EE21 && c <= 0x1EE22) || (c == 0x1EE24) || (c == 0x1EE27) || (c >= 0x1EE29 && c <= 0x1EE32) || (c >= 0x1EE34 && c <= 0x1EE37) || (c == 0x1EE39) || (c == 0x1EE3B) || (c == 0x1EE42) || (c == 0x1EE47) || (c == 0x1EE49) || (c == 0x1EE4B) || (c >= 0x1EE4D && c <= 0x1EE4F) || (c >= 0x1EE51 && c <= 0x1EE52) || (c == 0x1EE54) || (c == 0x1EE57) || (c == 0x1EE59) || (c == 0x1EE5B) || (c == 0x1EE5D) || (c == 0x1EE5F) || (c >= 0x1EE61 && c <= 0x1EE62) || (c == 0x1EE64) || (c >= 0x1EE67 && c <= 0x1EE6A) || (c >= 0x1EE6C && c <= 0x1EE72) || (c >= 0x1EE74 && c <= 0x1EE77) || (c >= 0x1EE79 && c <= 0x1EE7C) || (c == 0x1EE7E) || (c >= 0x1EE80 && c <= 0x1EE89) || (c >= 0x1EE8B && c <= 0x1EE9B) || (c >= 0x1EEA1 && c <= 0x1EEA3) || (c >= 0x1EEA5 && c <= 0x1EEA9) || (c >= 0x1EEAB && c <= 0x1EEBB));
}

BOOL isCodePointStrongLTR(UTF32Char c) {
  return (c >= 0x41 && c <= 0x5A) || (c >= 0x61 && c <= 0x7A) || (c == 0xAA) || (c == 0xB5) || (c == 0xBA) || (c >= 0xC0 && c <= 0xD6) || (c >= 0xD8 && c <= 0xF6) || (c >= 0xF8 && c <= 0x2B8) || (c >= 0x2BB && c <= 0x2C1) || (c >= 0x2D0 && c <= 0x2D1) || (c >= 0x2E0 && c <= 0x2E4) || (c == 0x2EE) || (c >= 0x370 && c <= 0x373) || (c >= 0x376 && c <= 0x377) || (c >= 0x37A && c <= 0x37D) || (c == 0x386) || (c >= 0x388 && c <= 0x38A) || (c == 0x38C) || (c >= 0x38E && c <= 0x3A1) || (c >= 0x3A3 && c <= 0x3F5) || (c >= 0x3F7 && c <= 0x482) || (c >= 0x48A && c <= 0x527) || (c >= 0x531 && c <= 0x556) || (c >= 0x559 && c <= 0x55F) || (c >= 0x561 && c <= 0x587) || (c == 0x589) || (c >= 0x903 && c <= 0x939) || (c == 0x93B) || (c >= 0x93D && c <= 0x940) || (c >= 0x949 && c <= 0x94C) || (c >= 0x94E && c <= 0x950) || (c >= 0x958 && c <= 0x961) || (c >= 0x964 && c <= 0x977) || (c >= 0x979 && c <= 0x97F) || (c >= 0x982 && c <= 0x983) || (c >= 0x985 && c <= 0x98C) || (c >= 0x98F && c <= 0x990) || (c >= 0x993 && c <= 0x9A8) || (c >= 0x9AA && c <= 0x9B0) || (c == 0x9B2) || (c >= 0x9B6 && c <= 0x9B9) || (c >= 0x9BD && c <= 0x9C0) || (c >= 0x9C7 && c <= 0x9C8) || (c >= 0x9CB && c <= 0x9CC) || (c == 0x9CE) || (c == 0x9D7) || (c >= 0x9DC && c <= 0x9DD) || (c >= 0x9DF && c <= 0x9E1) || (c >= 0x9E6 && c <= 0x9F1) || (c >= 0x9F4 && c <= 0x9FA) || (c == 0xA03) || (c >= 0xA05 && c <= 0xA0A) || (c >= 0xA0F && c <= 0xA10) || (c >= 0xA13 && c <= 0xA28) || (c >= 0xA2A && c <= 0xA30) || (c >= 0xA32 && c <= 0xA33) || (c >= 0xA35 && c <= 0xA36) || (c >= 0xA38 && c <= 0xA39) || (c >= 0xA3E && c <= 0xA40) || (c >= 0xA59 && c <= 0xA5C) || (c == 0xA5E) || (c >= 0xA66 && c <= 0xA6F) || (c >= 0xA72 && c <= 0xA74) || (c == 0xA83) || (c >= 0xA85 && c <= 0xA8D) || (c >= 0xA8F && c <= 0xA91) || (c >= 0xA93 && c <= 0xAA8) || (c >= 0xAAA && c <= 0xAB0) || (c >= 0xAB2 && c <= 0xAB3) || (c >= 0xAB5 && c <= 0xAB9) || (c >= 0xABD && c <= 0xAC0) || (c == 0xAC9) || (c >= 0xACB && c <= 0xACC) || (c == 0xAD0) || (c >= 0xAE0 && c <= 0xAE1) || (c >= 0xAE6 && c <= 0xAF0) || (c >= 0xB02 && c <= 0xB03) || (c >= 0xB05 && c <= 0xB0C) || (c >= 0xB0F && c <= 0xB10) || (c >= 0xB13 && c <= 0xB28) || (c >= 0xB2A && c <= 0xB30) || (c >= 0xB32 && c <= 0xB33) || (c >= 0xB35 && c <= 0xB39) || (c >= 0xB3D && c <= 0xB3E) || (c == 0xB40) || (c >= 0xB47 && c <= 0xB48) || (c >= 0xB4B && c <= 0xB4C) || (c == 0xB57) || (c >= 0xB5C && c <= 0xB5D) || (c >= 0xB5F && c <= 0xB61) || (c >= 0xB66 && c <= 0xB77) || (c == 0xB83) || (c >= 0xB85 && c <= 0xB8A) || (c >= 0xB8E && c <= 0xB90) || (c >= 0xB92 && c <= 0xB95) || (c >= 0xB99 && c <= 0xB9A) || (c == 0xB9C) || (c >= 0xB9E && c <= 0xB9F) || (c >= 0xBA3 && c <= 0xBA4) || (c >= 0xBA8 && c <= 0xBAA) || (c >= 0xBAE && c <= 0xBB9) || (c >= 0xBBE && c <= 0xBBF) || (c >= 0xBC1 && c <= 0xBC2) || (c >= 0xBC6 && c <= 0xBC8) || (c >= 0xBCA && c <= 0xBCC) || (c == 0xBD0) || (c == 0xBD7) || (c >= 0xBE6 && c <= 0xBF2) || (c >= 0xC01 && c <= 0xC03) || (c >= 0xC05 && c <= 0xC0C) || (c >= 0xC0E && c <= 0xC10) || (c >= 0xC12 && c <= 0xC28) || (c >= 0xC2A && c <= 0xC33) || (c >= 0xC35 && c <= 0xC39) || (c == 0xC3D) || (c >= 0xC41 && c <= 0xC44) || (c >= 0xC58 && c <= 0xC59) || (c >= 0xC60 && c <= 0xC61) || (c >= 0xC66 && c <= 0xC6F) || (c == 0xC7F) || (c >= 0xC82 && c <= 0xC83) || (c >= 0xC85 && c <= 0xC8C) || (c >= 0xC8E && c <= 0xC90) || (c >= 0xC92 && c <= 0xCA8) || (c >= 0xCAA && c <= 0xCB3) || (c >= 0xCB5 && c <= 0xCB9) || (c >= 0xCBD && c <= 0xCC4) || (c >= 0xCC6 && c <= 0xCC8) || (c >= 0xCCA && c <= 0xCCB) || (c >= 0xCD5 && c <= 0xCD6) || (c == 0xCDE) || (c >= 0xCE0 && c <= 0xCE1) || (c >= 0xCE6 && c <= 0xCEF) || (c >= 0xCF1 && c <= 0xCF2) || (c >= 0xD02 && c <= 0xD03) || (c >= 0xD05 && c <= 0xD0C) || (c >= 0xD0E && c <= 0xD10) || (c >= 0xD12 && c <= 0xD3A) || (c >= 0xD3D && c <= 0xD40) || (c >= 0xD46 && c <= 0xD48) || (c >= 0xD4A && c <= 0xD4C) || (c == 0xD4E) || (c == 0xD57) || (c >= 0xD60 && c <= 0xD61) || (c >= 0xD66 && c <= 0xD75) || (c >= 0xD79 && c <= 0xD7F) || (c >= 0xD82 && c <= 0xD83) || (c >= 0xD85 && c <= 0xD96) || (c >= 0xD9A && c <= 0xDB1) || (c >= 0xDB3 && c <= 0xDBB) || (c == 0xDBD) || (c >= 0xDC0 && c <= 0xDC6) || (c >= 0xDCF && c <= 0xDD1) || (c >= 0xDD8 && c <= 0xDDF) || (c >= 0xDF2 && c <= 0xDF4) || (c >= 0xE01 && c <= 0xE30) || (c >= 0xE32 && c <= 0xE33) || (c >= 0xE40 && c <= 0xE46) || (c >= 0xE4F && c <= 0xE5B) || (c >= 0xE81 && c <= 0xE82) || (c == 0xE84) || (c >= 0xE87 && c <= 0xE88) || (c == 0xE8A) || (c == 0xE8D) || (c >= 0xE94 && c <= 0xE97) || (c >= 0xE99 && c <= 0xE9F) || (c >= 0xEA1 && c <= 0xEA3) || (c == 0xEA5) || (c == 0xEA7) || (c >= 0xEAA && c <= 0xEAB) || (c >= 0xEAD && c <= 0xEB0) || (c >= 0xEB2 && c <= 0xEB3) || (c == 0xEBD) || (c >= 0xEC0 && c <= 0xEC4) || (c == 0xEC6) || (c >= 0xED0 && c <= 0xED9) || (c >= 0xEDC && c <= 0xEDF) || (c >= 0xF00 && c <= 0xF17) || (c >= 0xF1A && c <= 0xF34) || (c == 0xF36) || (c == 0xF38) || (c >= 0xF3E && c <= 0xF47) || (c >= 0xF49 && c <= 0xF6C) || (c == 0xF7F) || (c == 0xF85) || (c >= 0xF88 && c <= 0xF8C) || (c >= 0xFBE && c <= 0xFC5) || (c >= 0xFC7 && c <= 0xFCC) || (c >= 0xFCE && c <= 0xFDA) || (c >= 0x1000 && c <= 0x102C) || (c == 0x1031) || (c == 0x1038) || (c >= 0x103B && c <= 0x103C) || (c >= 0x103F && c <= 0x1057) || (c >= 0x105A && c <= 0x105D) || (c >= 0x1061 && c <= 0x1070) || (c >= 0x1075 && c <= 0x1081) || (c >= 0x1083 && c <= 0x1084) || (c >= 0x1087 && c <= 0x108C) || (c >= 0x108E && c <= 0x109C) || (c >= 0x109E && c <= 0x10C5) || (c == 0x10C7) || (c == 0x10CD) || (c >= 0x10D0 && c <= 0x1248) || (c >= 0x124A && c <= 0x124D) || (c >= 0x1250 && c <= 0x1256) || (c == 0x1258) || (c >= 0x125A && c <= 0x125D) || (c >= 0x1260 && c <= 0x1288) || (c >= 0x128A && c <= 0x128D) || (c >= 0x1290 && c <= 0x12B0) || (c >= 0x12B2 && c <= 0x12B5) || (c >= 0x12B8 && c <= 0x12BE) || (c == 0x12C0) || (c >= 0x12C2 && c <= 0x12C5) || (c >= 0x12C8 && c <= 0x12D6) || (c >= 0x12D8 && c <= 0x1310) || (c >= 0x1312 && c <= 0x1315) || (c >= 0x1318 && c <= 0x135A) || (c >= 0x1360 && c <= 0x137C) || (c >= 0x1380 && c <= 0x138F) || (c >= 0x13A0 && c <= 0x13F4) || (c >= 0x1401 && c <= 0x167F) || (c >= 0x1681 && c <= 0x169A) || (c >= 0x16A0 && c <= 0x16F0) || (c >= 0x1700 && c <= 0x170C) || (c >= 0x170E && c <= 0x1711) || (c >= 0x1720 && c <= 0x1731) || (c >= 0x1735 && c <= 0x1736) || (c >= 0x1740 && c <= 0x1751) || (c >= 0x1760 && c <= 0x176C) || (c >= 0x176E && c <= 0x1770) || (c >= 0x1780 && c <= 0x17B3) || (c == 0x17B6) || (c >= 0x17BE && c <= 0x17C5) || (c >= 0x17C7 && c <= 0x17C8) || (c >= 0x17D4 && c <= 0x17DA) || (c == 0x17DC) || (c >= 0x17E0 && c <= 0x17E9) || (c >= 0x1810 && c <= 0x1819) || (c >= 0x1820 && c <= 0x1877) || (c >= 0x1880 && c <= 0x18A8) || (c == 0x18AA) || (c >= 0x18B0 && c <= 0x18F5) || (c >= 0x1900 && c <= 0x191C) || (c >= 0x1923 && c <= 0x1926) || (c >= 0x1929 && c <= 0x192B) || (c >= 0x1930 && c <= 0x1931) || (c >= 0x1933 && c <= 0x1938) || (c >= 0x1946 && c <= 0x196D) || (c >= 0x1970 && c <= 0x1974) || (c >= 0x1980 && c <= 0x19AB) || (c >= 0x19B0 && c <= 0x19C9) || (c >= 0x19D0 && c <= 0x19DA) || (c >= 0x1A00 && c <= 0x1A16) || (c >= 0x1A19 && c <= 0x1A1B) || (c >= 0x1A1E && c <= 0x1A55) || (c == 0x1A57) || (c == 0x1A61) || (c >= 0x1A63 && c <= 0x1A64) || (c >= 0x1A6D && c <= 0x1A72) || (c >= 0x1A80 && c <= 0x1A89) || (c >= 0x1A90 && c <= 0x1A99) || (c >= 0x1AA0 && c <= 0x1AAD) || (c >= 0x1B04 && c <= 0x1B33) || (c == 0x1B35) || (c == 0x1B3B) || (c >= 0x1B3D && c <= 0x1B41) || (c >= 0x1B43 && c <= 0x1B4B) || (c >= 0x1B50 && c <= 0x1B6A) || (c >= 0x1B74 && c <= 0x1B7C) || (c >= 0x1B82 && c <= 0x1BA1) || (c >= 0x1BA6 && c <= 0x1BA7) || (c == 0x1BAA) || (c >= 0x1BAC && c <= 0x1BE5) || (c == 0x1BE7) || (c >= 0x1BEA && c <= 0x1BEC) || (c == 0x1BEE) || (c >= 0x1BF2 && c <= 0x1BF3) || (c >= 0x1BFC && c <= 0x1C2B) || (c >= 0x1C34 && c <= 0x1C35) || (c >= 0x1C3B && c <= 0x1C49) || (c >= 0x1C4D && c <= 0x1C7F) || (c >= 0x1CC0 && c <= 0x1CC7) || (c == 0x1CD3) || (c == 0x1CE1) || (c >= 0x1CE9 && c <= 0x1CEC) || (c >= 0x1CEE && c <= 0x1CF3) || (c >= 0x1CF5 && c <= 0x1CF6) || (c >= 0x1D00 && c <= 0x1DBF) || (c >= 0x1E00 && c <= 0x1F15) || (c >= 0x1F18 && c <= 0x1F1D) || (c >= 0x1F20 && c <= 0x1F45) || (c >= 0x1F48 && c <= 0x1F4D) || (c >= 0x1F50 && c <= 0x1F57) || (c == 0x1F59) || (c == 0x1F5B) || (c == 0x1F5D) || (c >= 0x1F5F && c <= 0x1F7D) || (c >= 0x1F80 && c <= 0x1FB4) || (c >= 0x1FB6 && c <= 0x1FBC) || (c == 0x1FBE) || (c >= 0x1FC2 && c <= 0x1FC4) || (c >= 0x1FC6 && c <= 0x1FCC) || (c >= 0x1FD0 && c <= 0x1FD3) || (c >= 0x1FD6 && c <= 0x1FDB) || (c >= 0x1FE0 && c <= 0x1FEC) || (c >= 0x1FF2 && c <= 0x1FF4) || (c >= 0x1FF6 && c <= 0x1FFC) || (c == 0x200E) || (c == 0x2071) || (c == 0x207F) || (c >= 0x2090 && c <= 0x209C) || (c == 0x2102) || (c == 0x2107) || (c >= 0x210A && c <= 0x2113) || (c == 0x2115) || (c >= 0x2119 && c <= 0x211D) || (c == 0x2124) || (c == 0x2126) || (c == 0x2128) || (c >= 0x212A && c <= 0x212D) || (c >= 0x212F && c <= 0x2139) || (c >= 0x213C && c <= 0x213F) || (c >= 0x2145 && c <= 0x2149) || (c >= 0x214E && c <= 0x214F) || (c >= 0x2160 && c <= 0x2188) || (c >= 0x2336 && c <= 0x237A) || (c == 0x2395) || (c >= 0x249C && c <= 0x24E9) || (c == 0x26AC) || (c >= 0x2800 && c <= 0x28FF) || (c >= 0x2C00 && c <= 0x2C2E) || (c >= 0x2C30 && c <= 0x2C5E) || (c >= 0x2C60 && c <= 0x2CE4) || (c >= 0x2CEB && c <= 0x2CEE) || (c >= 0x2CF2 && c <= 0x2CF3) || (c >= 0x2D00 && c <= 0x2D25) || (c == 0x2D27) || (c == 0x2D2D) || (c >= 0x2D30 && c <= 0x2D67) || (c >= 0x2D6F && c <= 0x2D70) || (c >= 0x2D80 && c <= 0x2D96) || (c >= 0x2DA0 && c <= 0x2DA6) || (c >= 0x2DA8 && c <= 0x2DAE) || (c >= 0x2DB0 && c <= 0x2DB6) || (c >= 0x2DB8 && c <= 0x2DBE) || (c >= 0x2DC0 && c <= 0x2DC6) || (c >= 0x2DC8 && c <= 0x2DCE) || (c >= 0x2DD0 && c <= 0x2DD6) || (c >= 0x2DD8 && c <= 0x2DDE) || (c >= 0x3005 && c <= 0x3007) || (c >= 0x3021 && c <= 0x3029) || (c >= 0x302E && c <= 0x302F) || (c >= 0x3031 && c <= 0x3035) || (c >= 0x3038 && c <= 0x303C) || (c >= 0x3041 && c <= 0x3096) || (c >= 0x309D && c <= 0x309F) || (c >= 0x30A1 && c <= 0x30FA) || (c >= 0x30FC && c <= 0x30FF) || (c >= 0x3105 && c <= 0x312D) || (c >= 0x3131 && c <= 0x318E) || (c >= 0x3190 && c <= 0x31BA) || (c >= 0x31F0 && c <= 0x321C) || (c >= 0x3220 && c <= 0x324F) || (c >= 0x3260 && c <= 0x327B) || (c >= 0x327F && c <= 0x32B0) || (c >= 0x32C0 && c <= 0x32CB) || (c >= 0x32D0 && c <= 0x32FE) || (c >= 0x3300 && c <= 0x3376) || (c >= 0x337B && c <= 0x33DD) || (c >= 0x33E0 && c <= 0x33FE) || (c == 0x3400) || (c == 0x4DB5) || (c == 0x4E00) || (c == 0x9FCC) || (c >= 0xA000 && c <= 0xA48C) || (c >= 0xA4D0 && c <= 0xA60C) || (c >= 0xA610 && c <= 0xA62B) || (c >= 0xA640 && c <= 0xA66E) || (c >= 0xA680 && c <= 0xA697) || (c >= 0xA6A0 && c <= 0xA6EF) || (c >= 0xA6F2 && c <= 0xA6F7) || (c >= 0xA722 && c <= 0xA787) || (c >= 0xA789 && c <= 0xA78E) || (c >= 0xA790 && c <= 0xA793) || (c >= 0xA7A0 && c <= 0xA7AA) || (c >= 0xA7F8 && c <= 0xA801) || (c >= 0xA803 && c <= 0xA805) || (c >= 0xA807 && c <= 0xA80A) || (c >= 0xA80C && c <= 0xA824) || (c == 0xA827) || (c >= 0xA830 && c <= 0xA837) || (c >= 0xA840 && c <= 0xA873) || (c >= 0xA880 && c <= 0xA8C3) || (c >= 0xA8CE && c <= 0xA8D9) || (c >= 0xA8F2 && c <= 0xA8FB) || (c >= 0xA900 && c <= 0xA925) || (c >= 0xA92E && c <= 0xA946) || (c >= 0xA952 && c <= 0xA953) || (c >= 0xA95F && c <= 0xA97C) || (c >= 0xA983 && c <= 0xA9B2) || (c >= 0xA9B4 && c <= 0xA9B5) || (c >= 0xA9BA && c <= 0xA9BB) || (c >= 0xA9BD && c <= 0xA9CD) || (c >= 0xA9CF && c <= 0xA9D9) || (c >= 0xA9DE && c <= 0xA9DF) || (c >= 0xAA00 && c <= 0xAA28) || (c >= 0xAA2F && c <= 0xAA30) || (c >= 0xAA33 && c <= 0xAA34) || (c >= 0xAA40 && c <= 0xAA42) || (c >= 0xAA44 && c <= 0xAA4B) || (c == 0xAA4D) || (c >= 0xAA50 && c <= 0xAA59) || (c >= 0xAA5C && c <= 0xAA7B) || (c >= 0xAA80 && c <= 0xAAAF) || (c == 0xAAB1) || (c >= 0xAAB5 && c <= 0xAAB6) || (c >= 0xAAB9 && c <= 0xAABD) || (c == 0xAAC0) || (c == 0xAAC2) || (c >= 0xAADB && c <= 0xAAEB) || (c >= 0xAAEE && c <= 0xAAF5) || (c >= 0xAB01 && c <= 0xAB06) || (c >= 0xAB09 && c <= 0xAB0E) || (c >= 0xAB11 && c <= 0xAB16) || (c >= 0xAB20 && c <= 0xAB26) || (c >= 0xAB28 && c <= 0xAB2E) || (c >= 0xABC0 && c <= 0xABE4) || (c >= 0xABE6 && c <= 0xABE7) || (c >= 0xABE9 && c <= 0xABEC) || (c >= 0xABF0 && c <= 0xABF9) || (c == 0xAC00) || (c == 0xD7A3) || (c >= 0xD7B0 && c <= 0xD7C6) || (c >= 0xD7CB && c <= 0xD7FB) || (c == 0xD800) || (c >= 0xDB7F && c <= 0xDB80) || (c >= 0xDBFF && c <= 0xDC00) || (c >= 0xDFFF && c <= 0xE000) || (c >= 0xF8FF && c <= 0xFA6D) || (c >= 0xFA70 && c <= 0xFAD9) || (c >= 0xFB00 && c <= 0xFB06) || (c >= 0xFB13 && c <= 0xFB17) || (c >= 0xFF21 && c <= 0xFF3A) || (c >= 0xFF41 && c <= 0xFF5A) || (c >= 0xFF66 && c <= 0xFFBE) || (c >= 0xFFC2 && c <= 0xFFC7) || (c >= 0xFFCA && c <= 0xFFCF) || (c >= 0xFFD2 && c <= 0xFFD7) || (c >= 0xFFDA && c <= 0xFFDC) || (c >= 0x10000 && c <= 0x1000B) || (c >= 0x1000D && c <= 0x10026) || (c >= 0x10028 && c <= 0x1003A) || (c >= 0x1003C && c <= 0x1003D) || (c >= 0x1003F && c <= 0x1004D) || (c >= 0x10050 && c <= 0x1005D) || (c >= 0x10080 && c <= 0x100FA) || (c == 0x10100) || (c == 0x10102) || (c >= 0x10107 && c <= 0x10133) || (c >= 0x10137 && c <= 0x1013F) || (c >= 0x101D0 && c <= 0x101FC) || (c >= 0x10280 && c <= 0x1029C) || (c >= 0x102A0 && c <= 0x102D0) || (c >= 0x10300 && c <= 0x1031E) || (c >= 0x10320 && c <= 0x10323) || (c >= 0x10330 && c <= 0x1034A) || (c >= 0x10380 && c <= 0x1039D) || (c >= 0x1039F && c <= 0x103C3) || (c >= 0x103C8 && c <= 0x103D5) || (c >= 0x10400 && c <= 0x1049D) || (c >= 0x104A0 && c <= 0x104A9) || (c == 0x11000) || (c >= 0x11002 && c <= 0x11037) || (c >= 0x11047 && c <= 0x1104D) || (c >= 0x11066 && c <= 0x1106F) || (c >= 0x11082 && c <= 0x110B2) || (c >= 0x110B7 && c <= 0x110B8) || (c >= 0x110BB && c <= 0x110C1) || (c >= 0x110D0 && c <= 0x110E8) || (c >= 0x110F0 && c <= 0x110F9) || (c >= 0x11103 && c <= 0x11126) || (c == 0x1112C) || (c >= 0x11136 && c <= 0x11143) || (c >= 0x11182 && c <= 0x111B5) || (c >= 0x111BF && c <= 0x111C8) || (c >= 0x111D0 && c <= 0x111D9) || (c >= 0x11680 && c <= 0x116AA) || (c == 0x116AC) || (c >= 0x116AE && c <= 0x116AF) || (c == 0x116B6) || (c >= 0x116C0 && c <= 0x116C9) || (c >= 0x12000 && c <= 0x1236E) || (c >= 0x12400 && c <= 0x12462) || (c >= 0x12470 && c <= 0x12473) || (c >= 0x13000 && c <= 0x1342E) || (c >= 0x16800 && c <= 0x16A38) || (c >= 0x16F00 && c <= 0x16F44) || (c >= 0x16F50 && c <= 0x16F7E) || (c >= 0x16F93 && c <= 0x16F9F) || (c >= 0x1B000 && c <= 0x1B001) || (c >= 0x1D000 && c <= 0x1D0F5) || (c >= 0x1D100 && c <= 0x1D126) || (c >= 0x1D129 && c <= 0x1D166) || (c >= 0x1D16A && c <= 0x1D172) || (c >= 0x1D183 && c <= 0x1D184) || (c >= 0x1D18C && c <= 0x1D1A9) || (c >= 0x1D1AE && c <= 0x1D1DD) || (c >= 0x1D360 && c <= 0x1D371) || (c >= 0x1D400 && c <= 0x1D454) || (c >= 0x1D456 && c <= 0x1D49C) || (c >= 0x1D49E && c <= 0x1D49F) || (c == 0x1D4A2) || (c >= 0x1D4A5 && c <= 0x1D4A6) || (c >= 0x1D4A9 && c <= 0x1D4AC) || (c >= 0x1D4AE && c <= 0x1D4B9) || (c == 0x1D4BB) || (c >= 0x1D4BD && c <= 0x1D4C3) || (c >= 0x1D4C5 && c <= 0x1D505) || (c >= 0x1D507 && c <= 0x1D50A) || (c >= 0x1D50D && c <= 0x1D514) || (c >= 0x1D516 && c <= 0x1D51C) || (c >= 0x1D51E && c <= 0x1D539) || (c >= 0x1D53B && c <= 0x1D53E) || (c >= 0x1D540 && c <= 0x1D544) || (c == 0x1D546) || (c >= 0x1D54A && c <= 0x1D550) || (c >= 0x1D552 && c <= 0x1D6A5) || (c >= 0x1D6A8 && c <= 0x1D6DA) || (c >= 0x1D6DC && c <= 0x1D714) || (c >= 0x1D716 && c <= 0x1D74E) || (c >= 0x1D750 && c <= 0x1D788) || (c >= 0x1D78A && c <= 0x1D7C2) || (c >= 0x1D7C4 && c <= 0x1D7CB) || (c >= 0x1F110 && c <= 0x1F12E) || (c >= 0x1F130 && c <= 0x1F169) || (c >= 0x1F170 && c <= 0x1F19A) || (c >= 0x1F1E6 && c <= 0x1F202) || (c >= 0x1F210 && c <= 0x1F23A) || (c >= 0x1F240 && c <= 0x1F248) || (c >= 0x1F250 && c <= 0x1F251) || (c == 0x20000) || (c == 0x2A6D6) || (c == 0x2A700) || (c == 0x2B734) || (c == 0x2B740) || (c == 0x2B81D) || (c >= 0x2F800 && c <= 0x2FA1D) || (c == 0xF0000) || (c == 0xFFFFD) || (c == 0x100000) || (c == 0x10FFFD);
}   

-(int)getBaseDirection {
  // Decode string into UTF32.
  NSData *utf32data = [self dataUsingEncoding:NSUTF32StringEncoding];
  // NSUTF32StringEncoding has the platform's byte-order, which should
  // be the same as UTF32Char's.
  UTF32Char *utf32chars = (UTF32Char *)[utf32data bytes];

  for (NSUInteger i = 0; i < self.length; i++) {
    // UTF32 is a fixed-length encoding, so utf32chars[i] will
    // always give us the i'th character.
    if (isCodePointStrongRTL(utf32chars[i]))
      return -1;
    if (isCodePointStrongLTR(utf32chars[i]))
      return 1;
  }
  return 0;
}

@end

Longer answer: Generating the functions isCodePointStrong{RTL,LTR}

  1. Create a script hex_numbers_to_dec_ranges_py,

    import sys
    from itertools import groupby, count
    
    numberlist = []
    for line in sys.stdin:
        numberlist.append(int(line, 16));
    
    def as_range(iterable): # not sure how to do this part elegantly
        l = list(iterable)
        if len(l) > 1:
            return '(c >= 0x{0:X} && c <= 0x{1:X})'.format(l[0], l[-1])
        else:
            return '(c == 0x{0:X})'.format(l[0])
    
    print ' || '.join(as_range(g) for _, g in groupby(numberlist, lambda n, c=count(): n-next(c)))
    

    (code shamelessly stolen from this excellent answer at StackExhange's Code Review).

  2. Run from a terminal:

    curl http://www.unicode.org/Public/UNIDATA/UnicodeData.txt > /tmp/UnicodeData.txt
    cat /tmp/UnicodeData.txt | awk -F';' '$5 == "R" || $5 == "AL"' | cut -d';' -f1 | python hex_numbers_to_dec_ranges.py > rtl.m
    cat /tmp/UnicodeData.txt | awk -F';' '$5 == "L"' | cut -d';' -f1 | python hex_numbers_to_dec_ranges.py > ltr.m
    rm /tmp/UnicodeData.txt
    

EDIT: As @masmor correctly noted, the for loop in getBaseDirection scans characters, and not bytes. Therefore, it should terminate after "character" number of iterations, and not "bytes" number of iterations. In other words, self.length times and not utf32data.length times. The code is now corrected.

查看更多
放我归山
5楼-- · 2019-03-14 02:46

I think the scan loop in -getBaseDirection should be for self.length times instead of utf32data.length in the accepted answer.

utf32data.length is the size in bytes while sizeof(UTF32Char) == 4, which would result in an overrun.

In action, the current code sporadically returns false positives for identical input, depending on what it overruns onto (maybe it'll segfault on a sufficiently bad day). Everything else seems to be working perfectly with the fix.

查看更多
登录 后发表回答