ikeh1024のブログ

ZennやQiitaに書くにはちょっと小粒なネタをこちらに書いています

NSStringのカテゴリ拡張: NFCへの正規化/安全なパーセントエンコーディング


  • NSString+Extension.h
#import <Foundation/Foundation.h>

@interface NSString (Extension)

- (NSString *)normalizeFormC;
- (NSString *)stringByRemovingPercentEncodingIfNeeded;

@end
  • NSString+Extension.m
#import "NSString+Extension.h"

@implementation NSString (Extension)

/**
 @brief  NFCに正規化する
 @return NFCに正規化されたNSString

 NSStringのデフォルトがNFCのためそちらに正規化する
 
 refs:
 [\[iOS\] 同じようにみえる文字が、\[NSString isEqualToString:\] で false になってしまう](https://qiita.com/plusadd/items/c2ec74eb2e19d068a421)
 [ファイルアップロードではNFC/NFD問題に気をつけろ!~MacファイルシステムにおけるUnicode正規化の闇~](https://zenn.dev/hacobell_dev/articles/68ccc92bffd6cc)
 */
- (NSString*)normalizeFormC {
    NSMutableString* _norstr = [NSMutableString stringWithString:self];
    CFStringNormalize((CFMutableStringRef)_norstr, kCFStringNormalizationFormC);
    
    return [NSString stringWithString:_norstr];
}

/**
 @brief 必要であればstringByRemovingPercentEncodingを行う
 
 refs:
 [stringByRemovingPercentEncoding](https://developer.apple.com/documentation/foundation/nsstring/1409569-stringbyremovingpercentencoding)
 >このメソッドは、パーセントでエンコードされていることがわかっている文字列に対してのみ呼び出す必要があります。パーセントエンコードされていない文字列に対してこのメ<200b><200b>ソッドを呼び出すと、
 >パーセント文字がパーセントエンコードされたシーケンスの始まりであると誤って解釈される可能性があります。
 */
- (NSString *)stringByRemovingPercentEncodingIfNeeded {
    NSCharacterSet *allowedCharacterSet = [NSCharacterSet URLQueryAllowedCharacterSet];
    NSCharacterSet *disallowedCharacterSet = [allowedCharacterSet invertedSet];
    NSRange range = [self rangeOfCharacterFromSet:disallowedCharacterSet];
    if (range.location != NSNotFound) {
        // パーセントエンコーディングされている場合
        return self.stringByRemovingPercentEncoding;
    } else {
        return self;
    }
}

@end