C# byDreamy postedApr 06, 2012

문자열 다루기

?

단축키

Prev이전 문서

Next다음 문서

ESC닫기

+ - Up Down Comment Print

문자열(String)은 문자(Char)의 배열입니다

안녕하세요. 박종명입니다. 닷넷 열아홉 번째 강좌를 진행하도록 하겠습니다<?xml:namespace prefix = o />

이번 시간에는 C#에서 문자열을 다루는 방법에 대해 알아보도록 하겠습니다

내용이 쉬우니 가볍게 읽어 주세요

문자열은 프로그램에서 자주 다루는 자료형 중에 하나입니다

사용자가 입력한 텍스트, DB에 저장된 텍스트, 프로그램이 직접 생성하는 텍스트, 웹 페이지를 랜더링 한 결과 HTML 등이

모두 문자열에 해당하며 이러한 문자열의 비교, 조합, 필터링, 검색 등 다양한 형태로 구현될 수 있습니다. 따라서 문자열을

익숙하게 다루는 것이 좋으며 이를 위해 이 강좌에서는 C#에서 문자열을 어떻게 정의하고 다루는지 그리고 문자열과 관련된

유용한 API 등에 대해 살펴보도록 하겠습니다

문자열은 문자의 집합이다

문자열은 말 그대로 문자의 열(), 즉 개별 문자들이 열거 된 자료형 입니다. 당연한 예기를 왜 할까요?

그건 C#에서 문자열이라는 자료형은 결국 개별 문자들의 배열이라는 점을 말씀 드리고 싶어서입니다

개별 문자는 char 자료형으로 표현 가능한데요. char의 모임, char 배열이 곧 문자열이 됩니다. 다음 코드를 보시죠

string str = "홍길동";

Console.WriteLine(str[0].ToString() + str[1].ToString() + str[2].ToString());

콘솔에 출력되는 결과는 문자열(‘홍길동’)이 그대로 출력되는데요

이렇듯 string 키워드를 사용해 표현한 문자열을 배열 첨자를 이용해 각 개별 문자를 참조할 수 있습니다

결국 string 이라는 문자열은 char의 배열이라는 것을 알 수 있는 것이죠

문자열은 String 객체로 표현됩니다

C#에서는 문자열을 위해 String 이라는 클래스를 미리 정의해 두었습니다

String 클래스는 문자열이라는 것을 추상화한 자료형인데요, 내부적으로 Char 배열로 문자열을 표현하며

문자열 연결, 검색, 삽입 등과 같은 문자열과 관련된 유용한 기능들을 제공해 줍니다

다음과 같이 String 객체를 생성할 수 있습니다

String str = new String(new char[]{'','',''});

Char 배열을 전달하여 String 클래스의 인스턴스를 생성하였습니다

그런데 이전의 예에서는 단순히 string str = "홍길동"의 형태로 문자열을 생성했는데 지금은 String 객체를 정의했습니다.

차이가 있을까요?

string 키워드는 String 클래스이 별칭입니다. 즉 문자열을 쉽게 다룰 수 있도록 string 키워드로 제공하는 것입니다.

따라서 String 객체로 문자열을 생성하나 string 키워드로 생성하나 동일한 것으로 보시면 되겠습니다

문자열은 참조타입 입니다

문자열이라는 것은 우리와 같은 인간에게는 매우 기본적인 형태이지만 컴퓨터에겐 조금 다릅니다

즉 컴퓨터는 아스키코드나 유니코드와 같은 텍스트 표현체계에 의해 정의된 문자만을 인식할 수 있으며 이 문자들의

집합인 문자열은 말 그대로 문자들의 배열로 인식하는 것입니다

이 말씀을 드리는 이유는 문자열이 너무나 익숙한 나머지 int, double 와 같이 string 도 값 타입(Value Type)으로

혼동하는 것을 방지하고자 함입니다

문자열은 개별 문자들의 집합이며 이는 문자들의 배열이 됩니다

그리고 string 키워드는 System.String 의 별칭이며 String 객체가 생성됩니다

참고로 int 는 값 타입이지만 int[] 은 참조타입이듯이 char 은 값 타입이지만 char[]은 참조타입입니다

. 결국 문자열은 참조타입이라는 것입니다

참조타입이지만 비교는 값 타입처럼 합니다

이전 C# 자료형 강좌에서 언급한 내용인데요.

string 는 참조타입이지만 상식적인(?) 문자열 처리를 위해 몇몇 연산자를 오버로딩 해 두었습니다

보통 객체와 같은 참조타입의 동일성비교(==)는 참조 값을 비교하는 것인 반면 string 객체는 참조가 아닌

값 자체(문자열자체)를 비교합니다. 이전 강좌의 글을 가져와 봅니다

string 객체의 동일성 비교

앞서 말씀 드렸듯이 string 키워드는 문자열을 표현하기 위해 닷넷이 기본으로 제공하는 참조형식 자료입니다.

string 은 비록 참조형식 이지만 동일성 비교에 있어서는 값 형식처럼 동작합니다

string s1 =”hello” string s2 = “hello” 로 선언하면 이 둘은 서로 다른 메모리에 할당되고

참조 값도 서로 다른 객체이지만 s1 = s2로 비교하면 동일하다는 결과가 나옵니다

이 것은 string 클래스 내부적으로 == 연산자를 오버로딩 하여 그 값 자체를 비교하도록 하기 때문입니다

문자열은 변경할 수 없는 객체입니다(immutable 객체입니다)

문자열은 한번 생성되면 변경되지 않습니다

그럼 문자열 변경은 어떻게 하나요? 사실 이 말은 문자열에 대한 메모리 측면을 말하는 것입니다

즉 문자열의 표면적인 변경은 가능하지만 내부적으로는 항상 새로운 문자열이 만들어 진다는 것이죠

다시 말해 기존 정의된 문자열의 메모리 영역이 변경되는 것이 아니라 새로운 String 객체가 생성되어 표면적으로는

변경된 것처럼 보입니다. 다음 코드를 보시죠

string str = "홍길동";

str += "만세"; //결과: 홍길동만세

홍길동이라는 String 객체를 생성한 뒤 이 객체에 만세라는 문자열을 덧붙였습니다

결과는 의도했던 대로 홍길동만세가 됩니다.

그러나 메모리 측면에서는 처음 생성한 str 과 이후 추가 문자가 덧 붙여진 str은 완전 다른 객체입니다

만세라는 글이 추가될 때 새로운 객체가 메모리에 할당되고 이 것을 str 이 다시 참조하도록 되는 것입니다.

(처음에 만든 홍길동이라는 객체는 사라지게 되는 것이죠(엄밀히 말해 가비지가 됩니다))

그림으로 표현하면 더 직관적일 수 있겠는데요. 말로만으로도 다 아시겠죠? ^^ (자바도 같은 개념입니다)

그럼 두 객체가 정말 다른 객체인지 증명(?)하기 위해 HashCode를 통해 객체 비교를 좀 해 보겠습니다

string str = "홍길동";

string strTemp = str; //str 객체 참조를 임시저장 해 둡니다

Console.WriteLine(str.GetHashCode() + " vs " + strTemp.GetHashCode());

str += "만세";

Console.WriteLine(str.GetHashCode() + " vs " + strTemp.GetHashCode());

 

<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /><?xml:namespace prefix = v />

결과를 보면 원래 문자열에 추가 문자를 덧붙이기 전과 후의 객체 해시 값이 일치하지 않는 것을 알 수 있습니다

성능을 위해서라면 String 대신 StringBuilder 를 고려하세요

문자열은 immutable 객체이기에 문자열에 대한 모든 사소한(?) 변경은 항상 새로운 객체 생성을 유발합니다.

소량의 문자열 또는 몇몇 단순 변경 등은 별 상관이 없겠으나 대량으로 문자열을 연결한다던 지, 문자열 변경 작업이

굉장히 빈번하다든지 할 경우에는 성능을 고려해 볼 필요가 있습니다

대량 문자열 변경은 그만큼의 대량의 문자열 객체 생성과 가비지화를 유발하기 때문에 성능상 좋지 못하기 때문입니다.

이러한 환경에서의 대안으로 StringBuilder 클래스가 있습니다

StringBuilder 역시 자바의 StringBuffer StringBuilder 와 거의 유사한 클래스라 보시면 되겠습니다

StringBuilder String 과는 달리 mutable 객체(변경 가능한 객체)입니다

다음은 StringBuilder 를 사용해 문자열을 연결하는 간단한 샘플입니다

System.Text.StringBuilder sb = new System.Text.StringBuilder();

sb.Append("one ");

sb.Append("two ");

sb.Append("three");

string str = sb.ToString();

System.Console.WriteLine(str);

MSDN의 설명을 보고 넘어가겠습니다.

성능 고려 사항

Concat AppendFormat 메서드는 새 데이터를 기존 String 또는 StringBuilder 개체에 연결합니다. String 개체 연결

작업에서는 항상 기존 문자열과 새 데이터로 새 개체를 만듭니다. StringBuilder 개체는 연결된 새 데이터를 수용할 버퍼를

유지합니다. 새 데이터는 공간이 있을 경우 버퍼 끝에 추가되고, 그렇지 않으면 더 큰 새로운 버퍼가 할당되고, 원래 버퍼의

데이터가 새 버퍼에 복사된 다음, 새 데이터가 새 버퍼에 추가됩니다.

String 또는 StringBuilder 개체에 대한 연결 작업의 성능은 얼마나 자주 메모리를 할당하는지에 따라 달라집니다.

StringBuilder 연결 작업에서는 StringBuilder 개체 버퍼가 너무 작아 새 데이터를 넣을 수 없는 경우에만 메모리가

할당되는 반면, String 연결 작업에서는 항상 메모리가 할당됩니다. 따라서 고정된 수의 String 개체를 연결하는 연결

작업에는 String 클래스가 더 적합합니다. 이 경우 개별 연결 작업이 컴파일러를 통해 단일 작업으로 결합될 수 있습니다.

임의의 개수의 문자열을 연결하는(: 루프에서 임의의 개수의 사용자 입력 문자열을 연결할 경우) 연결 작업에는 StringBuilder 개체가 더 적합합니다

문자열 유틸리티

문자열에 대한 기본적인 내용을 살펴 보았습니다

이제 닷넷 프레임워크에서 제공하는 문자열 조작 도우미 라이브러리를 샘플과 같이 알아 보겠습니다

사실 문자열 유틸리티가 별도로 존재하는 것이 아니라 대부분 String 클래스에서 통해 제공되는 기능입니다.

주요한 것 위주로 보겠습니다

1) 문자열 분리하기

String 클래스의 Split 메서드를 이용하면 문자열에서 특정 구분자를 기준으로 문자를 분리할 수 있습니다

오래된 방식이긴 합니다만, 특정 데이터의 복수 속성을 하나의 문자열로 구성하고 중간 중간에 ,(콤마) :(콜론) 과 같은

문자를 두어 구분하기도 했었는데요. 이 때 유용하게 사용되는 것이 Split 입니다

샘플> 어떤 사람의 이름,나이,주소와 같은 속성들을 하나의 문자열로 구성. ,(콤마)로 구분하기로 함

string str = "홍길동,20,경기도분당시";

Console.WriteLine("원본문자열: " + str);

string[] strArray = str.Split(',');

foreach (string s in strArray){

Console.WriteLine(s);

}

결과> 원본 문자열에서 구분자를 기준으로 배열로 분리된 것을 확인할 수 있습니다

구분자를 하나 이상 지정하여 해당 문자열에 복수의 구분자를 기준으로 분리할 수 있습니다

string str = "홍길동,20,경기도:분당시";

string[] strArray = str.Split(',',':'); //구분자 두개를 기준( , : )

2) 문자열 합치기

앞의 문자열 분리하기와 완전 반대되는 개념입니다

문자열 배열을 특정 구분자를 기준으로 합치는 것은 String 클래스의 Join 메서드를 통해 이루어집니다

앞 예제에서 분리된 결과인 문자열 배열(strArray)를 구분자 –(슬래시)를 기준으로 다시 합쳐 보겠습니다

string str2 = String.Join("-", strArray);

Console.WriteLine(str2); //결과: 홍길동-20-경기도분당시

3) 문자열 검색

문자열에서 특정 문자가 존재하는 지 검색하는 일이 많이 있습니다

String 클래스의 IndexOf, LastIndexOf, StartsWith, EndsWith 메서드로 문자열을 검색할 수 있습니다

IndexOf

문자열에서 특정 문자나 문자열이 존재하는 지 검사합니다.

만일 존재할 경우 해당 문자(문자열)이 시작하는 위치 값을 반환하고 존재하지 않으면 -1을 반환합니다

여기서 위치 값은 배열의 첨자로 0부터 시작합니다

string str = "동해물과백두산이마르고닳도록하느님이보우하사우리나라만세";

int postion = str.IndexOf("마르고닳도록");

Console.WriteLine(postion.ToString()); //결과: 8

만일 검색하고자 하는 문자(문자열)이 여럿 존재한다면 처음 일치하는 문자 위치를 반환합니다

LastIndexOf 도 있는데 이는 IndexOf와는 반대로 마지막에 일치하는 문자 위치를 반환합니다

LastIndexOf는 인터넷 주소와 같은 URL 에서 파일확장자나 폴더명을 검색하는 것과 같이 문자열의 뒤쪽 부분이 중요할 경우

많이 사용합니다 (이 두 메서드는 모두 대/소문자를 구분합니다)

StartWith

String 클래스의 StartWith 메서드를 이용하면 특정 문자열로 시작하는지 여부를 검사할 수 있습니다

string str = "홍길동 만세";

bool isResult = str.StartsWith("홍길");

Console.WriteLine(isResult); //결과: true

반대되는 개념인 EndsWith도 있는데요. 특정 문자열로 끝나는지 여부를 검사합니다

bool isResult = str.EndsWith("동 만세");

Console.WriteLine(isResult); //결과: true

4) 공백제거, /소문자 변경

사용자로부터 입력 받는 텍스트의 경우 정교하게 처리하지 않았다면 의도하지 않은 공백이 문자열에 포함되어 있을 수 있습니다

스페이스 바를 통한 문자열 중간 공백은 띄워 쓰기 목적이 있다고 하지만 앞/위 공백은 필요 없는 경우가 많습니다.

경우에 따라서는 의도하지 않는 결과가 나올 수 있으므로 앞/뒤 공백을 제거하는 일이 많이 있습니다. String 클래스의

Trim 관련 메서드가 이 역할을 수행합니다

string str = " 안녕하세요 ";

Console.WriteLine(str.Trim()); //결과: "안녕하세요"

Console.WriteLine(str.TrimStart()); //결과: "안녕하세요 "

Console.WriteLine(str.TrimEnd()); //결과: " 안녕하세요"

Trim 메서드로 공백을 제거와 더불어 앞/뒤의 특정 문자도 한번에 제거 할 수 있습니다

string str = "홍길동만세";

Console.WriteLine(str.Trim('',''));//결과: 길동만

그리고 영문의 경우 ToLower , ToUpper 메서드를 이용하면 대/소문자 변경이 가능합니다

5) 문자열 삽입, 교체, 자르기, 지우기

기존 문자열 중간에 새로운 문자를 추가할 수 있습니다

String 클래스의 Insert 메서드가 이용됩니다

string str = "홍길동 안녕";

Console.WriteLine(str.Insert(3, "")); //결과: 홍길동님 안녕

그리고 Replace 메서드로 문자열의 특정 문자를 다른 문자로 교체할 수 있습니다

string str = "홍길동 안녕";

Console.WriteLine(str.Replace("안녕", "방가")); //결과: 홍길동 방가

그리고 SubString 메서드로 문자열에서 특정 부분을 잘라 낼 수 있습니다

string str = "홍길동 안녕";

Console.WriteLine(str.Substring(1)); //결과: 길동 안녕

그리고 Remove 로 특정 부분을 제거할 수 있습니다

string str = "홍길동 안녕";

Console.WriteLine(str.Remove(1, 2)); //결과: 홍 안녕

6) 정규식을 이용한 문자열 검색

정규식을 이용하면 아주 복잡하고 유용한 형태의 문자열 검색 및 필터가 가능합니다

정규식은 닷넷의 기술이 아닙니다. 닷넷에서는 정규식 표현을 위한 클래스가 제공됩니다

정규식의 패턴 구성은 따로 학습을 하셔야 합니다(굉장히 재미있는 분야입니다. 서적 한 권 보면 감탄에 감탄을 합니다.

꼭 한번쯤은 관련 서적을 봐 두시기 바랍니다)

MSDN의 샘플을 소개하겠습니다. 문자열에서 전화번호 패턴에 일치 하는지 여부를 판별합니다

string[] numbers =

{

"123-456-7890",

"444-234-22450",

"690-203-6578",

"146-893-232",

"146-839-2322",

"4007-295-1111",

"407-295-1111",

"407-2-5555",

};

string sPattern = "^\\d{3}-\\d{3}-\\d{4}$"; //검색패턴(전화번호패턴: 3자리수 - 3자리수 - 4자리수)

foreach (string s in numbers){

System.Console.Write("{0,14}", s);

if (System.Text.RegularExpressions.Regex.IsMatch(s, sPattern)){

System.Console.WriteLine(" - valid");

}

else{

System.Console.WriteLine(" - invalid");

}

}

이상으로 문자열에 대한 강좌를 마치도록 하겠습니다

직접 여러 가지 상황을 가정하여 테스트 해 보시기 바랍니다

URL 에서 원하는 정보만 뽑아내기, 웹 페이지에서 이미지만 따로 뽑아내기, 게시물에서 욕설 걸러내기,

XML 태그 유효성 검사 등 주제를 잡고 시도해 보면 재미있습니다.

(다만 처음엔 간단한 상황으로 시작하세요. 첨부터 무리하면 본질을 흐립니다 ^^;)

오늘이 7월의 시작일이네요. 한 해의 절반이 시작되는 날입니다.

새해 계획이 어느 정도 구현(?)되고 있는지 점검해 보고 다시 맘을 먹고 두 번째 시작을 할 때 인 것 같아요

카페 회원님들 준비하시는 모든 것들 이루시길 바랍니다

그럼. 다음 강좌에서 뵙겠습니다


나눔글꼴 설치 안내


이 PC에는 나눔글꼴이 설치되어 있지 않습니다.

이 사이트를 나눔글꼴로 보기 위해서는
나눔글꼴을 설치해야 합니다.

설치 취소

Designed by sketchbooks.co.kr / sketchbook5 board skin

Sketchbook5, 스케치북5

Sketchbook5, 스케치북5

Sketchbook5, 스케치북5

Sketchbook5, 스케치북5