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
56 [Swift 3] HTTP Request 사용하기, 클래스 소스코드 및 사용법 digipine 2017.11.02 10123
55 OSX - Screen Serial Terminal - OSX에서 시리얼 터미널 사용하기 digipine 2017.11.03 7189
54 [iOS/Objective-C] __weak, __block 사용법 digipine 2021.02.16 5761
53 [Swift 3] TCPIP Socket 통신 클래스 소스 코드 및 사용법 digipine 2017.11.02 4945
52 [Objective-C] NSOperation과 NSOperationQueue를 사용하는 방법 - 설명 및 예제 엉뚱도마뱀 2018.03.14 4427
51 [iOS/macOS] 사설 인증서를 사용한 SSL HTTPS 통신 시 우회처리 digipine 2021.07.06 3446
50 iOS - Objective - C, URL 인코딩과 디코딩 digipine 2017.11.01 2154
49 [macOS] Sandbox 정책 극복기 Accessing Security Scoped Resource 1 file digipine 2017.11.02 2120
48 [Objective C] NSString 앞뒤 공백 문자 및 줄바꿈 문자 제거 digipine 2017.11.02 1811
47 [MacOS, Swift] 스크롤뷰, NSScrollView 사용법 엉뚱도마뱀 2018.11.01 1654
46 [swfit 4] 스위프트 Swift 동시성 동기화 정리 엉뚱도마뱀 2018.09.06 1528
45 OSX 사파리 최신 버전 폰트 변경하기 file digipine 2017.11.03 1338
» iOS - Objective C 정규식 사용법 2 digipine 2017.11.01 1326
43 iOS - UITextField의 Placeholder Color 색 변경하기 file digipine 2017.11.02 1311
42 [swift 4] 변경 사항 정리 file 엉뚱도마뱀 2018.07.23 1248
41 [iOS, MacOS] Singleton 싱글톤 패턴 사용하기 2 digipine 2017.11.02 1231
40 iOS - Openssl 빌드하기 digipine 2017.11.01 1211
39 MacOS mysql 비밀번호 분실 시 재설정하기 digipine 2017.11.14 1196
38 [macOS] Xcode 디버깅 시 Could not attach pid 오류 해결 file lizard2019 2023.06.05 1160
37 [iOS, MacOS] NSNotification, NSNotificationCenter 사용법 digipine 2017.11.02 1147
Board Pagination Prev 1 2 3 Next
/ 3