logo

English

이곳의 프로그래밍관련 정보와 소스는 마음대로 활용하셔도 좋습니다. 다만 쓰시기 전에 통보 정도는 해주시는 것이 예의 일것 같습니다. 질문이나 오류 수정은 siseong@gmail.com 으로 주세요. 감사합니다.

iOS - Objective C 정규식 사용법 2

by digipine posted Nov 01, 2017
?

Shortcut

PrevPrev Article

NextNext Article

Larger Font Smaller Font Up Down Go comment Print
?

Shortcut

PrevPrev Article

NextNext Article

Larger Font Smaller Font Up Down Go comment Print

정규식으로 일치하는 부분 문자열을 검색하는 방법

먼저 NSRegularExpression 개체를 만들고, 그것의 메서드에 NSString 객체를 전달하는 형태로 쓴다. 아무튼 설명하는 것보다 코드 보는 것이 빠르다.

NSString *string = @"「そんな正規表現で大丈夫か?」「大丈夫だ、問題ない」";
NSError *error   = nil;
NSRegularExpression *regexp =
 [NSRegularExpression regularExpressionWithPattern:@"「そんな(.+)で大丈夫か?」「(.+)」"
                                           options:0
                                             error:&error];
if (error != nil) {
 NSLog(@"%@", error);
} else {
 NSTextCheckingResult *match =
   [regexp firstMatchInString:string options:0 range:NSMakeRange(0, string.length)];

 NSLog(@"%d", match.numberOfRanges); // 3개

// 0번 index : 일치하는 모든 문자열
 NSLog(@"%@", [string substringWithRange:[match rangeAtIndex:0]]);

// 1번 index : 첫번째 패턴 "正規表現"
 NSLog(@"%@", [string substringWithRange:[match rangeAtIndex:1]]);

// 2번 index : 두번쨰 패턴 "大丈夫だ、問題ない"
 NSLog(@"%@", [string substringWithRange:[match rangeAtIndex:2]]);
}


다소 까다롭다. Ruby 쓰면 이렇게 끝나는데.
# coding: utf-8
if "「そんな正規表現で大丈夫か?」「大丈夫だ、問題ない」" =~ /「そんな(.+)で大丈夫か?」「(.+)」/
 puts $&
 puts $1
 puts $2
end
 

아무튼 Ruby나 Perl과 비교하는 것은 (적어도 문자열 조작이나 정규식에 관해서 말하면) 공정하지 않지만! 어쨌든 정규표현식으로 패턴을 찾을 수 있다.

덧붙여서 - firstMatchInString : options : range :라는 메서드 이름에서 알 수 있지만

이것은 첫번째로 일치하는 부분 밖에 가지고 오지 않는다. 일치하는 부분 모두 원한다면 - matchesInString : options : range :를 사용하면 NSTextCheckingResult 가 들어간 NSArray 가 되돌아 온다. 별도 반환값은 계속 가지고 있어야 아니라 일치하는 매순간  무언가 처리하려면 - enumerateMatchesInString : options : range : usingBlock : 사용할 수있다. 아까 - firstMatchInString : options : range :를 다시 이렇게 된다
NSRegularExpressionOptions options = 0;
NSRange range = NSMakeRange(0, string.length);
id block = ^(NSTextCheckingResult *match, NSMatchingFlags flag, BOOL *stop){
 NSLog(@"%d", match.numberOfRanges);
 NSLog(@"%@", [string substringWithRange:[match rangeAtIndex:0]]);
 NSLog(@"%@", [string substringWithRange:[match rangeAtIndex:1]]);
 NSLog(@"%@", [string substringWithRange:[match rangeAtIndex:2]]);
};
[regexp enumerateMatchesInString:string options:options range:range usingBlock:block];


 

Blocks 사용법은 이전 쓴 기사 를 읽어보셨는지 모르겠지만  그 기사를 쓴 시점에서 제대로 사용할 수있는 것이 Snow Leopard 뿐이였지만, 지금은라면 iPhone / iPad 모두 iOS4.0 을 전제로 만들 수 있고, 원래 NSRegularExpression 자체가 iOS4.0 이후 밖에 없기 때문에 NSRegularExpression를 사용할 수있는 환경이라면 Block 사용할 수 있으므로 문제 없다.

치환하기

정규식을 사용할 수있다면 가장하고 싶은 것은 Replace 일것이다. - stringByReplacingMatchesInString : options : range : withTemplate : 이용하면 된다

NSString *string = @"「そんな正規表現で大丈夫か?」「大丈夫だ、問題ない」";
 NSString *template =
   @"$0\n→($2砕け散る)\n→「神は言っている、ここで死ぬ運命ではないと」\n→「$1」「一番いいのを頼む」";
 NSRegularExpression *regexp =
   [NSRegularExpression regularExpressionWithPattern:@"「(そんな(.+)で大丈夫か?)」「.+」"
                                             options:0
                                               error:nil];
 NSString *replaced =
   [regexp stringByReplacingMatchesInString:string
                                    options:0
                                      range:NSMakeRange(0,string.length)
                               withTemplate:template];
 NSLog(@"%@",replaced);
 

처음에는 제대로 실행되지 않았다 しれと $ 0 라든지 $ 1이나 사용하고 있지만,

물론 제대로 치환된 문자열에서 캡처된 부분 문자열을 참조할 수 있을 것입니다.

그냥 - stringByReplacingMatchesInString : options : range : withTemplate : 는 문자열 자체를 치환하고있는 것이 아니라 인수 NSString 객체를 copy하여 치환후 반환된다. 그래서 원래 string 은 아무것도 변하지 않기 때문에 바꿀용도로 사용하려고 하면 실행이 안되는거 같고, 매번 문자열의 복사본을하기 때문에 때로는 자원이 낭비된다.

이 경우 - replaceMatchesInString : options : range : withTemplate : 를 쓴다. 기본적으로 - stringByReplacingMatchesInString : options : range : withTemplate : 같지만, 다음 사항을 다르다.

  • 인수 NSString은 없고 NSMutableString 을 가지고
  • 인수 개체의 복사본이 아니라 인수 개체 자체를 바꾸려면
  • 반환값은 바꿀 문자열이 아닌 정수 값으로 대체 개체 의 수를 반환
 

그래서, 몇몇 정규식 치환 문자열을 또 다른 정규 표현식으로 대체하여 같은 것을 할 경우는 아래 메서드를 사용해야한다.

참고로 위의 두 메소드는 일치하는 부분을 모두 바꾼다.

예를 들면 아래와 같은 코드로 하면 "大丈夫(か|だ)" 가 모두 교체된다.

NSString *string = @"「そんな正規表現で大丈夫か?」「大丈夫だ、問題ない」";
 NSString *template =
   @"チョ☆チョニッシーナ☆まっソコぶれっシュ☆エスボグリバンバーベーコンさんだね!";
 NSRegularExpression *regexp =
   [NSRegularExpression regularExpressionWithPattern:@"大丈夫(か|だ)、?"
                                             options:0
                                               error:nil];
 NSString *replaced =
   [regexp stringByReplacingMatchesInString:string
                                    options:0
                                      range:NSMakeRange(0,string.length)
                               withTemplate:template];
 NSLog(@"%@",replaced);


 

만약 일치하는 부분 내의 특정 부분을 치환하고 싶다면

- firstMatchInString : options : range : 나

- matchesInString : options : range :의

  NSTextCheckingResult 개체를 가져와 두었다가

- replacementStringForResult : inString : offset : template : 을 사용하면 되지만

좀 귀찮다.

 

RegexKitLite or NSRegularExpression

모두 써 본 소감을 말하자면, 개인적으로 RegexKitLite 의 NSString 에 메서드로 처리하는

방식의 API 가 사용하기 편했다. CoreFoundation 통해 쓰고 있기 때문에 성능도 나쁘지 않고, 비교적 초기에 Blocks 에 적응했거나 활발히 개발하고 있고 이미 RegexKitLite를 사용하고 있다면 무리해서 NSRegularExpression 로 갈아 탈 필요는 없다고 생각한다.
 

iOS4.0 이전 버전도 대상으로 한다면 다른 선택의 여지가 없고, 나중 왠지 NSRegularExpression 클래스는 iOS 밖에 없어 MacOSX 에서는 사용할 수 없다고 생각되기 때문에, iOS와 Mac에서도 동작과 같은 코드를 쓸 경우 역시 NSRegularExpression 사용할 수 없지 않을까..

 

NSRegularExpression 는 Foundation의 일부이므로, 정규식 치환을 사용하고 이 목적을 위해 외부의 코드로 분리하려고 프로젝트에 포함하거나, libicucore에 반드시 연결 ... 한다던지, 만일 iOS의 내부 구현이 바뀌거나 따위의 약관이 바뀌거나해서 아마 다시 갱신되지 않을까 생각되기도 한다 (안정성 때문이라던지), 때문에 앞으로 만들 애플 리케이션에서 4.0 이상만을 대상으로 하는 경우 NSRegularExpression 로 쓰는 걸까라고 생각되기도 한다.

 
TAG •

List of Articles
No. Subject Author Date Views
24 [Swift 3] HTTP Request 사용하기, 클래스 소스코드 및 사용법 digipine 2017.11.02 10201
23 [iOS, MacOS] NSArray 정렬 Sorting에 대해서 digipine 2017.11.02 1040
22 [iOS, MacOS] ATS 보안 정책 가이드 digipine 2017.11.02 839
21 iOS,OSX - CFSocket 사용법 digipine 2017.11.01 977
20 iOS - 코드 수행시간 측정하기 - getTickCount digipine 2017.11.01 1123
19 iOS - View 이동 전환 하기 총정리 digipine 2017.11.01 820
18 iOS - UILabel 에서 AttributeString 사용하기 digipine 2017.11.02 887
17 iOS - Thread Loop 내에서 UI 업데이트 방법 digipine 2017.11.01 533
16 iOS - Socket Nagle 알고리듬 OFF digipine 2017.11.01 470
15 iOS - Sleep Mode Blocking 방법, 앱실행시 슬립모드 진입 방지 digipine 2017.11.01 906
14 iOS - sizeWithFont 메소드 deprecated와 sizeWithAttributes digipine 2017.11.02 902
13 iOS - Query string을 Decode 하는 소스 digipine 2017.11.01 651
12 iOS - OpenURL으로 HTML에서 어플 실행 digipine 2017.11.01 892
11 iOS - Openssl 빌드하기 digipine 2017.11.01 1280
10 iOS - Objective-C 남아있는 메모리 공간 확인 방법 digipine 2017.11.01 495
9 iOS - Objective-C Callback for C++ digipine 2017.11.01 579
» iOS - Objective C 정규식 사용법 2 digipine 2017.11.01 1404
7 iOS - Objective - C, URL 인코딩과 디코딩 digipine 2017.11.01 2242
6 iOS - Objective - C 정규식 사용하기 digipine 2017.11.01 925
5 iOS - NSURLConnection로 다중 다운로드 구현 digipine 2017.11.01 630
Board Pagination Prev 1 2 Next
/ 2