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
36 [MacOS] Terminal 에서 zsh compinit: insecure directories 경고 제거하기 lizard2019 2021.04.30 567
35 iOS - OpenURL으로 HTML에서 어플 실행 digipine 2017.11.01 570
34 [iOS, MacOS] ATS 보안 정책 가이드 digipine 2017.11.02 571
33 iOS - Sleep Mode Blocking 방법, 앱실행시 슬립모드 진입 방지 digipine 2017.11.01 573
32 iOS - sizeWithFont 메소드 deprecated와 sizeWithAttributes digipine 2017.11.02 611
31 [macOS] Xcode 디버깅 시 Could not attach pid 오류 해결 file lizard2019 2023.06.05 635
30 iOS - UILabel 에서 AttributeString 사용하기 digipine 2017.11.02 640
29 iOS - BSD Socket 네트워크 프로그래밍 digipine 2017.11.01 665
28 [iOS, MacOS] NSArray 정렬 Sorting에 대해서 digipine 2017.11.02 668
27 The distance estimate iBeacon signal strength lizard2019 2019.10.25 696
26 macOS ARP Spoofing Attack file digipine 2020.09.17 699
25 XCode 8 업데이트 후 Code Sign Error 발생 시 해결법 1 digipine 2017.11.02 713
24 iOS - NSString의 언어 인코딩 메소드 정리 digipine 2017.11.01 717
23 WatermelonDB 'jsi/jsi.h' file not found 문제 해결 file digipine 2021.04.06 734
22 OpenAL PDF, Sample Source file digipine 2017.11.02 796
21 iOS - 코드 수행시간 측정하기 - getTickCount digipine 2017.11.01 848
20 iOS - Openssl 빌드하기 digipine 2017.11.01 947
19 iOS - BLE 장치용 ANCS Library for ANCS digipine 2017.11.02 950
» iOS - Objective C 정규식 사용법 2 digipine 2017.11.01 968
17 [swift 4] 변경 사항 정리 file 엉뚱도마뱀 2018.07.23 1020
Board Pagination Prev 1 2 3 Next
/ 3