알고리즘(코딩테스트)
string 관련 함수들 (tolower, isalpha, transform)
gbleem
2025. 1. 3. 14:55
문제 풀다가 접하게 된 string 처리 관련 함수를 정리해 보았다.
참고한 자료는
C++ 레퍼런스 - transform 함수
모두의 코드 C++ 레퍼런스 - transform 함수 작성일 : 2019-04-19 이 글은 21195 번 읽혔습니다. std::transform 은 범위 내 (first 부터 last 전 까지) 원소들 각각에 대해 인자로 전달한 함수를 실행 한 후, 그 결
modoocode.com
https://en.cppreference.com/w/
cppreference.com
Null-terminated strings: byte − multibyte − wide
en.cppreference.com
그리고 chat gpt이다.
1. tolower, toupper
int tolower(int ch);
- cctype 헤더에 정의되어있고, 함수 시그니처가 위처럼 생겼다.
- 문자를 10진수로 변환시켜 들어간 후, 대문자인 경우 소문자로 바꿔주는 함수이다.
- toupper는 말 그대로 대문자를 소문자로 바꿔준다.
- 만약 알파벳이 아닌 것이나 숫자, 공백등을 넣으면 값이 바뀌지 않고 그대로 출력된다.
- 예시코드
#include <iostream>
#include <cctype>
using namespace std;
int main()
{
string str = "ab12@ 2";
for (int i = 0; i < str.size(); ++i)
{
str[i] = toupper(str[i]);
}
for (auto s : str)
{
cout << s; //AB12@ 2
}
}
2. isalpha
int isalpha(int ch);
- islower 함수와 마찬가지로, 같은 형태의 함수이다. 이 함수 또한 cctype 헤더에 정의되어있다.
- input으로 char 를 받고 출력으로 문자인 경우 0이 아닌 값을, 문자가 아니면 0을 반환한다.
- 예시코드
#include <iostream>
#include <cctype>
using namespace std;
int main()
{
string str = "ab12@ 2";
for (int i = 0; i < str.size(); ++i)
{
if (isalpha(str[i]))
{
cout << "alpha : " << str[i] << "\n";
}
else if (isdigit(str[i]))
{
cout << "digit: " << str[i] << "\n";
}
//isalnum
}
}
3. transform
//1
template<class InputIt, class OutputIt, class UnaryOP>
OuputIt transform (InputIt first1, InputIt last1, OuputIt d_first, UnaryOp unary_op);
//2
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class UnaryOp >
ForwardIt2 transform( ExecutionPolicy&& policy,
ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 d_first, UnaryOp unary_op );
//3
template< class InputIt1, class InputIt2, class OutputIt, class BinaryOp >
OutputIt transform( InputIt1 first1, InputIt1 last1, InputIt2 first2,
OutputIt d_first, BinaryOp binary_op );
//4
template< class ExecutionPolicy, class ForwardIt1, class ForwardIt2, class ForwardIt3,
class BinaryOp >
ForwardIt3 transform( ExecutionPolicy&& policy,
ForwardIt1 first1, ForwardIt1 last1,
ForwardIt2 first2,
ForwardIt3 d_first, BinaryOp binary_op );
- 이 함수는 algorithm 헤더에 정의 되어 있다. 위처럼 네가지 방식으로 사용이 가능하다.
- 이 함수의 기본적인 동작은 주어진 입력 범위인 [first, last) 안에 원소 각각에 인자로 전달한 주어진 함수를 적용하고, 결과를 d_first부터 시작하는 iterator에 저장하는 함수이다.
- 예제를 통해서 사용법을 자세히 살펴보자
- 1번은 단항 함수(원소가 한개인 함수)를 사용하며, first1부터 last1 까지 unary_op를 적용한 값을 d_first로 시작하는 iterator에 저장하는 기능을 한다.
- 3번은 이상 함수(원소가 두개인 함수)를 통해 first1부터 last1까지와 first2 부터 시작되는 원소를 binary_op를 통해 쌍을 지어 함수를 실행하고 d_first에 저장한다.
- 이때 주의할 것은 first1부터 시작하는 iterator가 first2보다 크다면, end iterator보다 더 탐색했다는 런타임 에러가 발생한다.
- 2번과 4번은 각각의 방식에 ExecutionPolicy를 추가한 함수이다.
//단항함수 vector에 사용
void foo1()
{
vector<int> input = { 1,2,3,4,5 };
vector<int> output(input.size());
transform(input.begin(), input.end(), output.begin(), [](int x) {return x * x; });
for (auto i : input)
{
cout << i << " "; //1 2 3 4 5
}
cout << "\n";
for (auto o : output)
{
cout << o << " "; //1 4 9 16 25
}
}
//단항함수, string에 사용
void foo2()
{
string str("Hello");
transform(str.begin(), str.end(), str.begin(), toupper);
for (auto s : str)
{
cout << s ; //HELLO
}
}
//이항함수
void foo3()
{
vector<int> vec1 = { 1,2,3,4,5 };
vector<int> vec2 = { 10,20,30,40,50 };
vector<int> res(vec1.size());
transform(vec1.begin(), vec1.end(), vec2.begin(), res.begin(), [](int x, int y) {return x + y; });
for (auto r : res)
{
cout << r << " "; //11 22 33 44 55
}
cout << "\n";
}
- for_each VS transform
- 기본적인 동작은 비슷하지만, 반환 결과의 저장 유무가 가장 큰 차이점인 것 같다.
- for_each
- 원소를 수정하지 않는 것이 기본, 그러나 함수에 레퍼런스로 값을 받는다면 수정은 가능해 진다.
- 리턴값이 없고(함수 객체를 리턴하는 경우도 있다), 원소들을 순차대로 접근하는 것이 보장된다.
- transform
- 원소를 수정하고, 함수의 리턴값으로 해당 원소가 바뀐다.
- 모든 원소에 접근하는 것은 맞지만, 순서대로 원소들에 접근하는 것을 보장하지 않는다.
void to_lowercase_inplace(char& c) //reference
{
c = tolower(c);
}
void foo4()
{
string str("Hello!");
transform(str.begin(), str.end(), str.begin(), toupper);
cout << str << "\n";
for_each(str.begin(), str.end(), tolower);
cout << str << "\n";
for_each(str.begin(), str.end(), to_lowercase_inplace);
cout << str << "\n";
vector<int> vec = { 1,2,3,4,5 };
for_each(vec.begin(), vec.end(), [](int n) {n++; });
for (auto v : vec)
{
cout << v << " ";
}
cout << "\n";
for_each(vec.begin(), vec.end(), [](int& n) {n++; });
for (auto v : vec)
{
cout << v << " ";
}
}