수색…
소개
정규 표현식 (regexs 또는 regexps라고도 함)은 조작 된 문자열에서 일치 할 수있는 패턴을 나타내는 텍스트 구문입니다.
C ++ 11 에서 소개 된 Regular Expressions은 일치 문자열의 리턴 배열 또는 조작 된 문자열에서 일치 패턴을 대체하는 방법을 정의하는 다른 텍스트 구문을 선택적으로 지원할 수 있습니다.
통사론
- regex_match // 전체 문자 시퀀스가 정규식과 일치하는지 여부를 반환하고, 선택적으로 일치 객체를 캡처합니다.
- regex_search // 문자 시퀀스의 일부가 정규식과 일치하는지 여부를 반환하고, 선택적으로 일치 객체로 캡처합니다.
- regex_replace // 대체 형식 문자열을 통해 정규식에 의해 수정 된 입력 문자 시퀀스를 반환합니다.
- regex_token_iterator // 반복자에 의해 정의 된 문자 시퀀스, 반복 할 캡처 색인 목록 및 정규식으로 초기화됩니다. Dereferencing은 현재 색인 된 일치하는 정규 표현식을 반환합니다. 증분은 다음 캡처 색인으로 이동하거나 현재 마지막 색인에있는 경우 색인을 재설정하고 문자 순서에서 다음 정규 표현식 일치를 암시합니다
- regex_iterator // 이터레이터와 정규 표현식에 의해 정의 된 문자 시퀀스로 초기화됩니다. 역 참조는 전체 정규 표현식이 현재 일치하는 문자 시퀀스 부분을 반환합니다. Incrementing은 문자 시퀀스에서 다음 정규 표현식 일치를 찾습니다.
매개 변수
서명 | 기술 |
---|---|
bool regex_match(BidirectionalIterator first, BidirectionalIterator last, smatch& sm, const regex& re, regex_constraints::match_flag_type flags) | BidirectionalIterator 증가 및 감소 연산자 제공하는 모든 문자 반복자입니다 smatch 수 있습니다 cmatch 또는 기타 다른 변형 match_results 의 종류 받아 BidirectionalIterator smatch 정규식의 결과가 반환을 필요로하지 않으면 여부를 인수 ommitted 할 수있다 re 전체 문자와 일치를 first 와 last 정의 된 시퀀스 |
bool regex_match(const string& str, smatch& sm, const regex re&, regex_constraints::match_flag_type flags) | string 이어도 const char* 또는 L 값 string ,은 R 값 접수 기능 string 명시 적으로 삭제 smatch 있을 수 cmatch 또는 다른 어떤 다른 변형 match_results 유형 수용 str smatch 인수 경우 ommitted 될 수있다 regex의 결과는 필요 없다. re 가 str 의해 정의 된 전체 문자 시퀀스와 일치하는지 여부를 반환 한다. |
기본 regex_match 및 regex_search 예제
const auto input = "Some people, when confronted with a problem, think \"I know, I'll use regular expressions.\""s;
smatch sm;
cout << input << endl;
// If input ends in a quotation that contains a word that begins with "reg" and another word begining with "ex" then capture the preceeding portion of input
if (regex_match(input, sm, regex("(.*)\".*\\breg.*\\bex.*\"\\s*$"))) {
const auto capture = sm[1].str();
cout << '\t' << capture << endl; // Outputs: "\tSome people, when confronted with a problem, think\n"
// Search our capture for "a problem" or "# problems"
if(regex_search(capture, sm, regex("(a|d+)\\s+problems?"))) {
const auto count = sm[1] == "a"s ? 1 : stoi(sm[1]);
cout << '\t' << count << (count > 1 ? " problems\n" : " problem\n"); // Outputs: "\t1 problem\n"
cout << "Now they have " << count + 1 << " problems.\n"; // Ouputs: "Now they have 2 problems\n"
}
}
regex_replace 예제
이 코드는 다양한 가새 스타일을 사용하여 하나의 진정한 가새 스타일 로 변환합니다.
const auto input = "if (KnR)\n\tfoo();\nif (spaces) {\n foo();\n}\nif (allman)\n{\n\tfoo();\n}\nif (horstmann)\n{\tfoo();\n}\nif (pico)\n{\tfoo(); }\nif (whitesmiths)\n\t{\n\tfoo();\n\t}\n"s;
cout << input << regex_replace(input, regex("(.+?)\\s*\\{?\\s*(.+?;)\\s*\\}?\\s*"), "$1 {\n\t$2\n}\n") << endl;
regex_token_iterator 예제
std::regex_token_iterator
는 쉼표로 구분 된 값 파일의 요소 를 추출 하는 엄청난 도구를 제공 합니다 . 이터레이터는 반복의 이점을 제외하고는 다른 메소드가 고민하는 곳에서 쉼표를 이스케이프 처리 할 수 있습니다.
const auto input = "please split,this,csv, ,line,\\,\n"s;
const regex re{ "((?:[^\\\\,]|\\\\.)+)(?:,|$)" };
const vector<string> m_vecFields{ sregex_token_iterator(cbegin(input), cend(input), re, 1), sregex_token_iterator() };
cout << input << endl;
copy(cbegin(m_vecFields), cend(m_vecFields), ostream_iterator<string>(cout, "\n"));
regex iterator가있는 주목할만한 점은 regex
이 L 값이어야한다는 것입니다. R 값은 작동하지 않습니다 .
regex_iterator 예제
캡처 처리가 반복적으로 수행되어야하는 경우 regex_iterator
가 좋은 선택입니다. regex_iterator
Dereferencing하면 match_result
반환됩니다. 이는 상호 의존성이있는 조건부 캡처 또는 캡처에 적합합니다. C ++ 코드를 토큰 화하려고한다고 가정 해 봅시다. 주어진:
enum TOKENS {
NUMBER,
ADDITION,
SUBTRACTION,
MULTIPLICATION,
DIVISION,
EQUALITY,
OPEN_PARENTHESIS,
CLOSE_PARENTHESIS
};
이 문자열을 다음과 같이 regex_iterator
와 함께 const auto input = "42/2 + -8\t=\n(2 + 2) * 2 * 2 -3"s
으로 regex_iterator
수 있습니다.
vector<TOKENS> tokens;
const regex re{ "\\s*(\\(?)\\s*(-?\\s*\\d+)\\s*(\\)?)\\s*(?:(\\+)|(-)|(\\*)|(/)|(=))" };
for_each(sregex_iterator(cbegin(input), cend(input), re), sregex_iterator(), [&](const auto& i) {
if(i[1].length() > 0) {
tokens.push_back(OPEN_PARENTHESIS);
}
tokens.push_back(i[2].str().front() == '-' ? NEGATIVE_NUMBER : NON_NEGATIVE_NUMBER);
if(i[3].length() > 0) {
tokens.push_back(CLOSE_PARENTHESIS);
}
auto it = next(cbegin(i), 4);
for(int result = ADDITION; it != cend(i); ++result, ++it) {
if (it->length() > 0U) {
tokens.push_back(static_cast<TOKENS>(result));
break;
}
}
});
match_results<string::const_reverse_iterator> sm;
if(regex_search(crbegin(input), crend(input), sm, regex{ tokens.back() == SUBTRACTION ? "^\\s*\\d+\\s*-\\s*(-?)" : "^\\s*\\d+\\s*(-?)" })) {
tokens.push_back(sm[1].length() == 0 ? NON_NEGATIVE_NUMBER : NEGATIVE_NUMBER);
}
regex 반복자가있는 주목할만한 점은 regex
인수가 L 값이어야하고 R 값이 작동하지 않는다는 것입니다. Visual Studio regex_iterator Bug?
문자열 분할하기
std::vector<std::string> split(const std::string &str, std::string regex)
{
std::regex r{ regex };
std::sregex_token_iterator start{ str.begin(), str.end(), r, -1 }, end;
return std::vector<std::string>(start, end);
}
split("Some string\t with whitespace ", "\\s+"); // "Some", "string", "with", "whitespace"
한정 기호
const string input
유효성을 검사 할 전화 번호가 주어진다고 가정 해 보겠습니다. regex_match(input, regex("\\d*"))
또는 하나 이상의 한정 기호 : regex_match(input, regex("\\d+"))
그러나 0 이상의 수량 입력을 요구할 수 있습니다 . input
이 잘못된 숫자 문자열 (예 : "123")을 포함하는 경우 이들 둘 모두가 실제로 부족합니다. n 개 이상의 한정 기호 를 사용하여 최소 7 자리를 확보하도록하십시오.
regex_match(input, regex("\\d{7,}"))
이렇게하면 최소한 숫자의 전화 번호를 얻을 수 있지만 input
너무 긴 숫자 문자열 (예 : "123456789012")이 포함될 수 있습니다. 따라서 n과 m 사이의 한정 기호를 사용하여 input
이 7 자리 이상 11 이하가되도록하십시오.
regex_match(input, regex("\\d{7,11}"));
이것은 우리를 더 가깝게하지만 [7, 11]의 범위에있는 불법 숫자 문자열은 여전히 받아 들여집니다 : "123456789"그래서 게으른 한정 기호로 국가 코드를 선택적으로 만듭니다.
regex_match(input, regex("\\d?\\d{7,10}"))
게으른 한정 기호 는 가능한 한 적은 수의 문자 와 일치하므로,이 문자가 일치하는 유일한 방법은 \d{7,10}
에 일치하는 문자가 이미 10 개있는 경우입니다. (첫 번째 문자를 탐욕스럽게 맞추려면 \d{0,1}
을 사용해야합니다.) lazy 수량 한정자 는 다른 수량 기호에 추가 될 수 있습니다.
자, 지역 코드가 존재하는 경우, 지역 코드를 선택 사항으로 만들고 국가 코드 만 수락하는 방법은 무엇입니까?
regex_match(input, regex("(?:\\d{3,4})?\\d{7}"))
이 마지막 정규식에서 \d{7}
은 7 자리 가 필요합니다 . 이 7 자리에는 선택적으로 3 자리 또는 4 자리가 선행됩니다.
우리는 , \d{3,4}?\d{7}
\d{3,4}?
같은 게으른 한정 기호를 추가하지 않았다는 것에 유의하십시오 \d{3,4}?
3 또는 4 자 중 하나와 일치하며 3을 선호합니다. 대신 비 캡처 그룹을 최대 한 번만 일치시키고 일치하지 않는 것을 선호합니다. input
"1234567"과 같은 지역 번호가 포함되지 않으면 불일치가 발생합니다.
정량 항목의 끝으로, 나는 당신이 사용할 수있는 다른 추기 한정 기호, 소유격 정량을 언급하고 싶습니다. 게으른 정량 또는 소유 정량 중 하나는 정량에 추가 할 수 있습니다. 소유량 한정 기호 의 유일한 기능은 그것을 말함으로써 정규식 엔진을 돕는 것이며, 이러한 문자를 탐욕스럽게 받아들이고 정규 표현식이 실패하더라도 그것을 포기하지 않습니다 . regex_match(input, regex("\\d{3,4}+\\d{7}))
"1234567890 "과 같은 input
은 \d{3,4}+
와 일치하지 않으므로 일치하는 3이 정규 표현식을 허용하는 경우에도 \d{3,4}+
는 항상 4 문자와 일치합니다.
소유량 한정 기호 는 수량화 된 토큰이 일치 가능한 문자 수를 제한 할 때 가장 잘 사용 됩니다 . 예 :
regex_match(input, regex("(?:.*\\d{3,4}+){3}"))
input
에 다음 중 하나가 포함 된 경우 일치시키는 데 사용할 수 있습니다.
123 456 7890
123-456-7890
(123)456-7890
(123) 456-7890
하지만이 정규식이 정말 빛날 때 input
에 불법 입력이 들어있을 때입니다.
12345 - 67890
소유량 한정 기호 가 없으면 regex 엔진은 돌아가서 .*
와 3 또는 4 자의 모든 조합을 테스트하여 일치 가능한 조합을 찾을 수 있는지 확인해야합니다. 소유 지정자 로 정규 표현식은 2 번째 소유 한정 기호가 생략 된 '0'문자를 시작하고 정규 표현식 엔진은 .*
을 조정하여 \d{3,4}
가 일치하도록합니다. 이 정규식 단지 실패 할 수없는 경우, 더 다시 추적 이전 있는지 확인하기 위해 수행되지 않습니다 .*
조정 경기를 허용 할 수 있습니다.
앵커
C ++는 단 4 개의 앵커를 제공합니다.
-
^
문자열의 시작을 선언합니다. - 문자열의 끝을 나타내는
$
-
\b
\W
문자 또는 문자열의 시작 또는 끝을 나타내는\b
-
\B
는\w
문자를 표시합니다.
이제 우리는 그것의 기호와 번호를 캡처 할 예를 들어 가정 해 봅시다 :
auto input = "+1--12*123/+1234"s;
smatch sm;
if(regex_search(input, sm, regex{ "(?:^|\\b\\W)([+-]?\\d+)" })) {
do {
cout << sm[1] << endl;
input = sm.suffix().str();
} while(regex_search(input, sm, regex{ "(?:^\\W|\\b\\W)([+-]?\\d+)" }));
}
여기서 중요한 점은 앵커는 어떤 문자도 소비하지 않는다는 것입니다.