📄 pcrecpp.cc
字号:
// Copyright (c) 2005, Google Inc.// All rights reserved.//// Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions are// met://// * Redistributions of source code must retain the above copyright// notice, this list of conditions and the following disclaimer.// * Redistributions in binary form must reproduce the above// copyright notice, this list of conditions and the following disclaimer// in the documentation and/or other materials provided with the// distribution.// * Neither the name of Google Inc. nor the names of its// contributors may be used to endorse or promote products derived from// this software without specific prior written permission.//// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.//// Author: Sanjay Ghemawat#include <stdlib.h>#include <stdio.h>#include <ctype.h>#include <limits.h> /* for SHRT_MIN, USHRT_MAX, etc */#include <assert.h>#include <errno.h>#include <string>#include <algorithm>#include "config.h"// We need this to compile the proper dll on windows/msys. This is copied// from pcre_internal.h. It would probably be better just to include that.#define PCRE_DEFINITION /* Win32 __declspec(export) trigger for .dll */#include "pcre.h"#include "pcre_stringpiece.h"#include "pcrecpp.h"namespace pcrecpp {// Maximum number of args we can setstatic const int kMaxArgs = 16;static const int kVecSize = (1 + kMaxArgs) * 3; // results + PCRE workspace// Special object that stands-in for no argumentArg no_arg((void*)NULL);// If a regular expression has no error, its error_ field points herestatic const string empty_string;// If the user doesn't ask for any options, we just use this onestatic RE_Options default_options;void RE::Init(const char* pat, const RE_Options* options) { pattern_ = pat; if (options == NULL) { options_ = default_options; } else { options_ = *options; } error_ = &empty_string; re_full_ = NULL; re_partial_ = NULL; re_partial_ = Compile(UNANCHORED); if (re_partial_ != NULL) { // Check for complicated patterns. The following change is // conservative in that it may treat some "simple" patterns // as "complex" (e.g., if the vertical bar is in a character // class or is escaped). But it seems good enough. if (strchr(pat, '|') == NULL) { // Simple pattern: we can use position-based checks to perform // fully anchored matches re_full_ = re_partial_; } else { // We need a special pattern for anchored matches re_full_ = Compile(ANCHOR_BOTH); } }}RE::~RE() { if (re_full_ != NULL && re_full_ != re_partial_) (*pcre_free)(re_full_); if (re_partial_ != NULL) (*pcre_free)(re_partial_); if (error_ != &empty_string) delete error_;}pcre* RE::Compile(Anchor anchor) { // First, convert RE_Options into pcre options int pcre_options = 0; pcre_options = options_.all_options(); // Special treatment for anchoring. This is needed because at // runtime pcre only provides an option for anchoring at the // beginning of a string (unless you use offset). // // There are three types of anchoring we want: // UNANCHORED Compile the original pattern, and use // a pcre unanchored match. // ANCHOR_START Compile the original pattern, and use // a pcre anchored match. // ANCHOR_BOTH Tack a "\z" to the end of the original pattern // and use a pcre anchored match. const char* compile_error; int eoffset; pcre* re; if (anchor != ANCHOR_BOTH) { re = pcre_compile(pattern_.c_str(), pcre_options, &compile_error, &eoffset, NULL); } else { // Tack a '\z' at the end of RE. Parenthesize it first so that // the '\z' applies to all top-level alternatives in the regexp. string wrapped = "(?:"; // A non-counting grouping operator wrapped += pattern_; wrapped += ")\\z"; re = pcre_compile(wrapped.c_str(), pcre_options, &compile_error, &eoffset, NULL); } if (re == NULL) { if (error_ == &empty_string) error_ = new string(compile_error); } return re;}/***** Matching interfaces *****/bool RE::FullMatch(const StringPiece& text, const Arg& ptr1, const Arg& ptr2, const Arg& ptr3, const Arg& ptr4, const Arg& ptr5, const Arg& ptr6, const Arg& ptr7, const Arg& ptr8, const Arg& ptr9, const Arg& ptr10, const Arg& ptr11, const Arg& ptr12, const Arg& ptr13, const Arg& ptr14, const Arg& ptr15, const Arg& ptr16) const { const Arg* args[kMaxArgs]; int n = 0; if (&ptr1 == &no_arg) goto done; args[n++] = &ptr1; if (&ptr2 == &no_arg) goto done; args[n++] = &ptr2; if (&ptr3 == &no_arg) goto done; args[n++] = &ptr3; if (&ptr4 == &no_arg) goto done; args[n++] = &ptr4; if (&ptr5 == &no_arg) goto done; args[n++] = &ptr5; if (&ptr6 == &no_arg) goto done; args[n++] = &ptr6; if (&ptr7 == &no_arg) goto done; args[n++] = &ptr7; if (&ptr8 == &no_arg) goto done; args[n++] = &ptr8; if (&ptr9 == &no_arg) goto done; args[n++] = &ptr9; if (&ptr10 == &no_arg) goto done; args[n++] = &ptr10; if (&ptr11 == &no_arg) goto done; args[n++] = &ptr11; if (&ptr12 == &no_arg) goto done; args[n++] = &ptr12; if (&ptr13 == &no_arg) goto done; args[n++] = &ptr13; if (&ptr14 == &no_arg) goto done; args[n++] = &ptr14; if (&ptr15 == &no_arg) goto done; args[n++] = &ptr15; if (&ptr16 == &no_arg) goto done; args[n++] = &ptr16; done: int consumed; int vec[kVecSize]; return DoMatchImpl(text, ANCHOR_BOTH, &consumed, args, n, vec, kVecSize);}bool RE::PartialMatch(const StringPiece& text, const Arg& ptr1, const Arg& ptr2, const Arg& ptr3, const Arg& ptr4, const Arg& ptr5, const Arg& ptr6, const Arg& ptr7, const Arg& ptr8, const Arg& ptr9, const Arg& ptr10, const Arg& ptr11, const Arg& ptr12, const Arg& ptr13, const Arg& ptr14, const Arg& ptr15, const Arg& ptr16) const { const Arg* args[kMaxArgs]; int n = 0; if (&ptr1 == &no_arg) goto done; args[n++] = &ptr1; if (&ptr2 == &no_arg) goto done; args[n++] = &ptr2; if (&ptr3 == &no_arg) goto done; args[n++] = &ptr3; if (&ptr4 == &no_arg) goto done; args[n++] = &ptr4; if (&ptr5 == &no_arg) goto done; args[n++] = &ptr5; if (&ptr6 == &no_arg) goto done; args[n++] = &ptr6; if (&ptr7 == &no_arg) goto done; args[n++] = &ptr7; if (&ptr8 == &no_arg) goto done; args[n++] = &ptr8; if (&ptr9 == &no_arg) goto done; args[n++] = &ptr9; if (&ptr10 == &no_arg) goto done; args[n++] = &ptr10; if (&ptr11 == &no_arg) goto done; args[n++] = &ptr11; if (&ptr12 == &no_arg) goto done; args[n++] = &ptr12; if (&ptr13 == &no_arg) goto done; args[n++] = &ptr13; if (&ptr14 == &no_arg) goto done; args[n++] = &ptr14; if (&ptr15 == &no_arg) goto done; args[n++] = &ptr15; if (&ptr16 == &no_arg) goto done; args[n++] = &ptr16; done: int consumed; int vec[kVecSize]; return DoMatchImpl(text, UNANCHORED, &consumed, args, n, vec, kVecSize);}bool RE::Consume(StringPiece* input, const Arg& ptr1, const Arg& ptr2, const Arg& ptr3, const Arg& ptr4, const Arg& ptr5, const Arg& ptr6, const Arg& ptr7, const Arg& ptr8, const Arg& ptr9, const Arg& ptr10, const Arg& ptr11, const Arg& ptr12, const Arg& ptr13, const Arg& ptr14, const Arg& ptr15, const Arg& ptr16) const { const Arg* args[kMaxArgs]; int n = 0; if (&ptr1 == &no_arg) goto done; args[n++] = &ptr1; if (&ptr2 == &no_arg) goto done; args[n++] = &ptr2; if (&ptr3 == &no_arg) goto done; args[n++] = &ptr3; if (&ptr4 == &no_arg) goto done; args[n++] = &ptr4; if (&ptr5 == &no_arg) goto done; args[n++] = &ptr5; if (&ptr6 == &no_arg) goto done; args[n++] = &ptr6; if (&ptr7 == &no_arg) goto done; args[n++] = &ptr7; if (&ptr8 == &no_arg) goto done; args[n++] = &ptr8; if (&ptr9 == &no_arg) goto done; args[n++] = &ptr9; if (&ptr10 == &no_arg) goto done; args[n++] = &ptr10; if (&ptr11 == &no_arg) goto done; args[n++] = &ptr11; if (&ptr12 == &no_arg) goto done; args[n++] = &ptr12; if (&ptr13 == &no_arg) goto done; args[n++] = &ptr13; if (&ptr14 == &no_arg) goto done; args[n++] = &ptr14; if (&ptr15 == &no_arg) goto done; args[n++] = &ptr15; if (&ptr16 == &no_arg) goto done; args[n++] = &ptr16; done: int consumed; int vec[kVecSize]; if (DoMatchImpl(*input, ANCHOR_START, &consumed, args, n, vec, kVecSize)) { input->remove_prefix(consumed); return true; } else { return false; }}bool RE::FindAndConsume(StringPiece* input, const Arg& ptr1, const Arg& ptr2, const Arg& ptr3, const Arg& ptr4, const Arg& ptr5, const Arg& ptr6, const Arg& ptr7, const Arg& ptr8, const Arg& ptr9, const Arg& ptr10, const Arg& ptr11, const Arg& ptr12, const Arg& ptr13, const Arg& ptr14, const Arg& ptr15, const Arg& ptr16) const { const Arg* args[kMaxArgs]; int n = 0; if (&ptr1 == &no_arg) goto done; args[n++] = &ptr1; if (&ptr2 == &no_arg) goto done; args[n++] = &ptr2; if (&ptr3 == &no_arg) goto done; args[n++] = &ptr3; if (&ptr4 == &no_arg) goto done; args[n++] = &ptr4; if (&ptr5 == &no_arg) goto done; args[n++] = &ptr5; if (&ptr6 == &no_arg) goto done; args[n++] = &ptr6; if (&ptr7 == &no_arg) goto done; args[n++] = &ptr7; if (&ptr8 == &no_arg) goto done; args[n++] = &ptr8; if (&ptr9 == &no_arg) goto done; args[n++] = &ptr9; if (&ptr10 == &no_arg) goto done; args[n++] = &ptr10; if (&ptr11 == &no_arg) goto done; args[n++] = &ptr11; if (&ptr12 == &no_arg) goto done; args[n++] = &ptr12; if (&ptr13 == &no_arg) goto done; args[n++] = &ptr13; if (&ptr14 == &no_arg) goto done; args[n++] = &ptr14; if (&ptr15 == &no_arg) goto done; args[n++] = &ptr15; if (&ptr16 == &no_arg) goto done; args[n++] = &ptr16; done: int consumed; int vec[kVecSize]; if (DoMatchImpl(*input, UNANCHORED, &consumed, args, n, vec, kVecSize)) { input->remove_prefix(consumed); return true; } else { return false; }}bool RE::Replace(const StringPiece& rewrite, string *str) const { int vec[kVecSize]; int matches = TryMatch(*str, 0, UNANCHORED, vec, kVecSize); if (matches == 0) return false; string s; if (!Rewrite(&s, rewrite, *str, vec, matches)) return false; assert(vec[0] >= 0); assert(vec[1] >= 0); str->replace(vec[0], vec[1] - vec[0], s); return true;}int RE::GlobalReplace(const StringPiece& rewrite, string *str) const { int count = 0; int vec[kVecSize]; string out; int start = 0; int lastend = -1; for (; start <= static_cast<int>(str->length()); count++) { int matches = TryMatch(*str, start, UNANCHORED, vec, kVecSize); if (matches <= 0) break; int matchstart = vec[0], matchend = vec[1]; assert(matchstart >= start); assert(matchend >= matchstart); if (matchstart == matchend && matchstart == lastend) { // advance one character if we matched an empty string at the same // place as the last match occurred if (start < static_cast<int>(str->length())) out.push_back((*str)[start]); start++; } else { out.append(*str, start, matchstart - start); Rewrite(&out, rewrite, *str, vec, matches); start = matchend; lastend = matchend; count++; } } if (count == 0) return 0; if (start < static_cast<int>(str->length())) out.append(*str, start, str->length() - start); swap(out, *str); return count;}bool RE::Extract(const StringPiece& rewrite, const StringPiece& text, string *out) const { int vec[kVecSize]; int matches = TryMatch(text, 0, UNANCHORED, vec, kVecSize); if (matches == 0) return false; out->erase(); return Rewrite(out, rewrite, text, vec, matches);}/***** Actual matching and rewriting code *****/int RE::TryMatch(const StringPiece& text, int startpos, Anchor anchor, int *vec, int vecsize) const {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -