建筑网站设计,怎么提交网站收录,平面设计公司企业logo设计,网站开发职业生涯规划书C正则表达式全攻略#xff1a;从基础到高级应用 一、基础知识二、正则表达式的基本匹配三、C中使用正则表达式四、高级正则表达式五、实践示例六、性能优化6.1、编译正则表达式6.2、避免过度使用回溯6.3、优化匹配算法 七、总结 一、基础知识
正则表达式是一种用于匹配、搜索… C正则表达式全攻略从基础到高级应用 一、基础知识二、正则表达式的基本匹配三、C中使用正则表达式四、高级正则表达式五、实践示例六、性能优化6.1、编译正则表达式6.2、避免过度使用回溯6.3、优化匹配算法 七、总结 一、基础知识
正则表达式是一种用于匹配、搜索和编辑文本的字符串模式。它由一系列字符和特殊符号构成可以灵活地表达文本的模式、结构和特征。正则表达式在各种编程语言和应用程序中广泛应用包括C。它可以用来在文本中查找特定模式的字符串、验证输入的格式、提取信息和进行文本替换等操作。
正则表达式的基本元素包括普通字符如字母、数字和符号、特殊字符如通配符、边界符和量词以及捕获组和反向引用等高级功能。通过组合这些元素可以构建复杂的匹配规则实现强大的文本处理功能。
C中使用正则表达式的优势 强大的文本处理能力正则表达式提供了灵活的方式来描述文本模式和规则能够轻松地实现复杂的文本匹配、搜索和提取功能。 通过正则表达式可以快速验证用户输入的数据格式是否符合要求提高了数据的准确性和一致性。 正则表达式可以轻松地进行文本替换和格式化操作例如批量替换文本中的内容或者格式化输出文本。 正则表达式可以用较短的代码实现复杂的文本处理功能提高代码的可读性和简洁性。 正则表达式可以用于日志分析、数据提取、文本解析等各种场景为 C 提供了强大的文本处理工具。
在 C 中使用正则表达式通过提供的regex头文件来实现。基本语法和规则 普通字符包括字母、数字和一些符号表示自身字符。 特殊字符包括元字符如 ^、$、.、*、、?、|、\ 等用于描述匹配规则。 量词指定前面模式出现的次数如 *零次或多次、一次或多次、?零次或一次{m,n}出现次数范围为m到n次等。 转义字符使用 \ 来转义特殊字符使其成为普通字符。 字符类用 [ ] 表示一组字符中的任意一个。比如 [abc] 匹配 “a”、“b” 或 “c” 中的任意一个。 捕获组用( )将模式组合成一个单元可以获取匹配的子串。
在 C 的 regex 头文件中常用的类有 std::regex、std::smatch 和 std::regex_match 等通过这些类可以实现正则表达式的匹配、搜索和提取。例如使用 std::regex_match 函数来检查一个字符串是否与指定的正则表达式匹配使用 std::smatch 类来存储匹配的结果。
正则表达式在 C 中的基本语法和规则与其他语言中的正则表达式基本相同但在具体的实现上可能会有一些差异。可查看官方介绍。
二、正则表达式的基本匹配 匹配单个字符 使用普通字符进行匹配例如正则表达式 a 可以匹配字符串中的单个字符 “a”。使用元字符.进行匹配任意单个字符例如正则表达式 s. 可以匹配字符串中的 “sa”、“sb”、“sc” 等。 匹配多个字符 使用量词*匹配前面的字符出现零次或多次例如正则表达式ab*可以匹配 “a”, “ab”, “abb”, “abbb” 等。使用量词匹配前面的字符出现一次或多次例如正则表达式ab可以匹配 “ab”, “abb”, “abbb” 等。使用量词?匹配前面的字符出现零次或一次例如正则表达式ab?可以匹配 “a”, “ab” 等。使用花括号{m,n}匹配前面的字符出现m到n次例如正则表达式a{2,4}可以匹配 “aa”, “aaa”, “aaaa”。 匹配起始和结束位置 使用锚字符^匹配字符串的起始位置例如正则表达式^start可以匹配以 “start” 开头的字符串。使用锚字符$匹配字符串的结束位置例如正则表达式end$可以匹配以 “end” 结尾的字符串。
当使用正则表达式进行文本匹配时需要匹配字符类character class和排除字符类negated character class。字符类用来匹配一个字符集合中的任何一个字符而排除字符类则用来匹配除指定字符集合之外的任何字符。
在正则表达式中使用方括号[]来表示一个字符类方括号内包含要匹配的字符集合。例如
[aeiou] 可以匹配任何一个小写元音字母。[A-Za-z] 可以匹配任何一个大写或小写字母。[0-9] 可以匹配任何一个数字字符。
另外可以在方括号内使用连字符-来表示一个范围如[a-z]表示匹配任何一个小写字母。
相反使用脱字符^在字符类内表示排除字符类。例如
[^aeiou] 可以匹配除了小写元音字母之外的任何字符。
正则表达式支持匹配重复出现的模式使用不同的量词来指定重复匹配的规则。
常用的量词
*匹配前面的模式零次或多次。匹配前面的模式一次或多次。?匹配前面的模式零次或一次。{n}匹配前面的模式恰好n次。{n,}匹配前面的模式至少n次。{n,m}匹配前面的模式至少n次且至多m次。
例如
a* 可以匹配零个或多个 “a”。a 可以匹配一个或多个 “a”。a? 可以匹配零个或一个 “a”。a{3} 可以匹配恰好三个 “a”。a{2,4} 可以匹配两个到四个 “a”。
正则表达式还有两个重要的概念是锚点anchors和分组groups。
锚点用来指定匹配的位置常用的锚点
^匹配字符串的开始位置。$匹配字符串的结束位置。\b匹配单词边界。\B匹配非单词边界。
例如
^abc 可以匹配以 “abc” 开头的字符串。xyz$ 可以匹配以 “xyz” 结尾的字符串。\bword\b 可以匹配单独的 “word” 单词。\Bword\B 可以匹配 “word” 单词的内部。
分组则用来把对模式的匹配结果进行分组并对每个分组进行单独的处理。分组用括号()表示。例如
(ab) 可以匹配 “ab”、“abab”、“ababab” 等。(a|b) 可以匹配 “a” 或者 “b”。
三、C中使用正则表达式
在C中使用正则表达式需要包含 regex 头文件并使用 std 命名空间。使用std::regex类来创建正则表达式对象。正则表达式对象可以用来存储和表示一个特定的正则表达式模式。使用正则表达式来进行匹配和搜索。在C中使用std::regex_search函数和std::regex_match函数来实现这些功能。
示例
#include iostream
#include regexint main() {std::string text Hello, this is a sample text with some numbers 12345.;std::regex pattern(\\d); // 匹配一个或多个数字std::smatch matches; // 用于存储匹配结果if (std::regex_search(text, matches, pattern)) {std::cout Found match: matches.str() std::endl;} else {std::cout No match found. std::endl;}return 0;
}使用std::regex_search函数来搜索文本text并且尝试找到与正则表达式模式pattern匹配的内容。还使用了std::smatch类来存储匹配的结果并打印出匹配的内容。
还可以使用std::regex_match函数来检查整个字符串是否完全匹配正则表达式模式。
if (std::regex_match(text, pattern)) {std::cout Full match found std::endl;
} else {std::cout No full match found std::endl;
}此外可以使用C中的正则表达式库来提取和替换匹配的部分。C标准库中的std::regex类和std::regex_replace函数可以完成这些任务。
示例
#include iostream
#include regexint main() {std::string text The cat sat on the mat.;std::regex pattern(\\b(cat)\\b); // 匹配整个单词catstd::sregex_iterator it(text.begin(), text.end(), pattern);std::sregex_iterator end;for (; it ! end; it) {std::smatch match *it;std::cout Match found: match.str() at position match.position() std::endl;}// 替换匹配的部分std::string replaced_text std::regex_replace(text, pattern, dog);std::cout Replaced text: replaced_text std::endl;return 0;
}使用std::sregex_iterator来迭代查找匹配的结果然后使用std::regex_replace函数来替换匹配的部分。这里还使用了position()函数来获取匹配的位置。
四、高级正则表达式
1较为复杂的模式匹配。C的正则表达式库支持一系列功能强大的正则表达式语法可以用于更复杂的模式匹配需求实现更精细的文本匹配和提取。 示例
#include iostream
#include regexint main() {std::string text The cat sat on the mat. The dog sat on the rug.;std::regex pattern(\\b(\\w)\\ssat\\son\\sthe\\s(\\w)\\b); // 匹配类似xxx sat on the xxx的句子std::sregex_iterator it(text.begin(), text.end(), pattern);std::sregex_iterator end;for (; it ! end; it) {std::smatch match *it;std::cout Match found: match.str() std::endl;std::cout First captured group: match[1].str() std::endl;std::cout Second captured group: match[2].str() std::endl;}return 0;
}2使用捕获组和回溯。捕获组允许在正则表达式中标记并捕获特定的部分而回溯则允许在替换文本中引用捕获的内容。 示例
#include iostream
#include regexint main() {std::string text The price is $10.99. The total is $25.50.;std::regex pattern(\\$(\\d\\.\\d)); // 匹配美元金额std::string replaced_text std::regex_replace(text, pattern, ¥$1); // 使用捕获组的内容进行替换std::cout Replaced text: replaced_text std::endl;return 0;
}使用了捕获组来匹配金额并在替换文本中使用了$1来引用捕获的内容进行替换。这里的$1表示使用第一个捕获组的内容来替换匹配的部分。
3懒惰匹配与贪婪匹配。懒惰匹配和贪婪匹配用于描述量词的匹配方式。贪婪匹配尽可能多地匹配字符串而懒惰匹配则尽可能少地匹配字符串。
在C的正则表达式中使用?来表示懒惰匹配。示例
#include iostream
#include regexint main() {std::string text The cat sat on the mat. The dog sat on the rug.;std::regex greedy_pattern(s[a-z]t); // 贪婪匹配尽可能多地匹配s和t之间的字母std::regex lazy_pattern(s[a-z]?t); // 懒惰匹配尽可能少地匹配s和t之间的字母std::sregex_iterator it_greedy(text.begin(), text.end(), greedy_pattern);std::sregex_iterator end_greedy;for (; it_greedy ! end_greedy; it_greedy) {std::smatch match *it_greedy;std::cout Greedy Match found: match.str() std::endl;}std::sregex_iterator it_lazy(text.begin(), text.end(), lazy_pattern);std::sregex_iterator end_lazy;for (; it_lazy ! end_lazy; it_lazy) {std::smatch match *it_lazy;std::cout Lazy Match found: match.str() std::endl;}return 0;
}贪婪匹配尽可能多地匹配了s和t之间的字母而懒惰匹配尽可能少地匹配了s和t之间的字母。
4向前和向后查找。向前和向后查找提供了一种基于当前匹配位置的相对定位功能能够查找在特定位置之前或之后的模式。这对于需要匹配特定上下文的情况非常有用。
示例
#include iostream
#include regexint main() {std::string text The quick brown fox jumps over the lazy dog;std::regex forward_pattern(\\b\\w(?\\sfox)); // 向前查找匹配fox之前的单词std::regex backward_pattern((?brown\\s)\\w\\b); // 向后查找匹配brown之后的单词std::smatch match;if (std::regex_search(text, match, forward_pattern)) {std::cout Forward match found: match.str() std::endl;}if (std::regex_search(text, match, backward_pattern)) {std::cout Backward match found: match.str() std::endl;}return 0;
}向前查找使用 (?\sfox) 来匹配 fox 之前的单词向后查找使用 (?brown\s) 来匹配 brown 之后的单词。
五、实践示例
1数据验证与格式化。邮箱地址进行验证和格式化
#include iostream
#include regex
#include stringbool isValidEmail(const std::string email) {std::regex pattern(R([a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,}));return std::regex_match(email, pattern);
}std::string formatPhoneNumber(const std::string phoneNumber) {std::regex pattern(R(\b(\d{3})(\d{3})(\d{4})\b));return std::regex_replace(phoneNumber, pattern, R($1-$2-$3));
}int main() {// 邮箱验证std::string email 2505756506qq.com;if (isValidEmail(email)) {std::cout Email is valid std::endl;} else {std::cout Invalid email std::endl;}// 电话号码格式化std::string phoneNumber 12345678901;std::string formattedNumber formatPhoneNumber(phoneNumber);std::cout Formatted phone number: formattedNumber std::endl;return 0;
}验证是通过std::regex_match实现而格式化是通过std::regex_replace实现。
2文本提取与分析。提取文本中的数字并进行分析
#include iostream
#include regex
#include string
#include vectorstd::vectorint extractNumbers(const std::string input) {std::vectorint numbers;std::regex pattern(R(\d));std::sregex_iterator iter(input.begin(), input.end(), pattern);std::sregex_iterator end;for (; iter ! end; iter) {numbers.push_back(std::stoi(iter-str()));}return numbers;
}int main() {std::string text The price of the item is $250. The weight is 5.5 pounds.;std::vectorint numbers extractNumbers(text);std::cout Extracted numbers: ;for (int num : numbers) {std::cout num ;}std::cout std::endl;// 分析提取的数字int sum 0;for (int num : numbers) {sum num;}std::cout Sum of the numbers: sum std::endl;return 0;
}3日志文件分析。提取和分析日志文件中的关键信息例如时间戳、IP地址、错误信息等
#include iostream
#include fstream
#include regex
#include stringvoid analyzeLogFile(const std::string filename) {std::ifstream file(filename);if (!file.is_open()) {std::cerr Error opening file filename std::endl;return;}std::regex timePattern(R((\d{2}:\d{2}:\d{2})));std::regex ipPattern(R((\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})));std::regex errorPattern(R(error|ERROR));std::string line;while (std::getline(file, line)) {std::smatch timeMatch;std::smatch ipMatch;std::smatch errorMatch;if (std::regex_search(line, timeMatch, timePattern) std::regex_search(line, ipMatch, ipPattern) std::regex_search(line, errorMatch, errorPattern)) {std::cout Timestamp: timeMatch[0] , IP address: ipMatch[0] , Error: errorMatch[0] std::endl;}}file.close();
}int main() {analyzeLogFile(example.log);return 0;
}4高级的文本处理应用。
#include iostream
#include regex
#include stringvoid advancedTextProcessing(const std::string text) {// 通过正则表达式替换文本中的日期格式std::regex datePattern(R(\b(\d{1,2})/(\d{1,2})/(\d{4})\b));std::string processedText std::regex_replace(text, datePattern, $3-$1-$2);std::cout Processed text with date format replaced: processedText std::endl;// 提取文本中的URLstd::regex urlPattern(R((https?://\S)));std::sregex_iterator iter(text.begin(), text.end(), urlPattern);std::sregex_iterator end;std::cout Extracted URLs: ;for (; iter ! end; iter) {std::cout iter-str() ;}std::cout std::endl;// 使用正则表达式分组提取文本中的标题和内容std::regex articlePattern(R(title(.*?)/title.*?content(.*?)/content), std::regex::dotall);std::smatch match;if (std::regex_search(text, match, articlePattern)) {std::cout Title: match[1].str() std::endl;std::cout Content: match[2].str() std::endl;}
}int main() {std::string sampleText Todays date is 12/30/2023. Visit our website at https://www.baidu.com/ for more information. titleSample Title/titlecontentThis is a sample content./content;advancedTextProcessing(sampleText);return 0;
}六、性能优化
6.1、编译正则表达式 预先编译正则表达式对于会重复使用的正则表达式建议在程序初始化阶段就进行编译以避免在每次匹配时都重新编译。可以使用 std::regex 的构造函数来进行编译。 std::regex regExpr(pattern); // 预先编译正则表达式在可能的情况下尽量使用简单的正则表达式模式避免过于复杂和耗时的匹配规则。 在正则表达式中尽量使用非贪婪量词*?、?、{n, m}?来进行匹配以避免贪婪匹配导致的性能问题。 如果可能的话尽量在正则表达式中使用具体的字符串而不是通用的通配符以减少匹配的复杂度。 如果程序需要频繁使用多个正则表达式可以将它们预先编译并存储起来以提高性能。 std::unordered_mapstd::string, std::regex regexCache;
regexCache[datePattern] std::regex(R((\d{1,2})/(\d{1,2})/(\d{4})));6.2、避免过度使用回溯
在编写正则表达式时避免过度使用回溯是非常重要的因为回溯会导致正则表达式的性能下降尤其是在处理长文本或复杂模式时。 尽量使用非贪婪量词例如*?、?、{n,m}?以避免匹配过程中出现不必要的回溯。 避免在正则表达式中过度使用嵌套的重复因为这可能导致回溯的增加。尽量简化模式减少嵌套的深度。 使用原子组: 原子组可以避免回溯因此可以使用它们来限制回溯发生的范围。 如果只需要匹配特定的固定字符串最好直接使用字符串匹配函数而不是使用正则表达式。 有些正则表达式引擎可以将正则表达式编译为确定性有限自动机DFA这种方法可以避免回溯提高匹配性能。 预先编译正则表达式: 如前面所述在程序初始化阶段就进行编译可以避免在每次匹配时都重新编译提高性能。
6.3、优化匹配算法 不同的算法在不同的场景下有不同的性能表现。例如在处理大型文本时基于有限自动机DFA的算法会比回溯算法更高效。 回溯是一种耗时的操作尽量避免使得正则表达式需要进行大量回溯可以通过优化正则表达式模式或使用非贪婪量词来减少回溯次数。 如果只需要匹配特定的固定字符串直接使用字符串匹配函数如 strstr 或其它语言的等效函数可能比使用正则表达式更高效。 如果需要频繁匹配相同的正则表达式可以缓存匹配结果以减少重复的匹配操作。 对输入文本进行预处理例如去除不需要进行匹配的部分可以减少匹配的复杂度提高匹配性能。 对于大量需要匹配的数据使用多线程并行匹配来加快匹配速度。
七、总结
正则表达式应用方向 输入验证用于验证用户输入的数据是否符合特定的格式如电子邮件地址、电话号码、日期、密码等。 数据提取从文本中提取特定模式的数据例如从网页中提取链接、从日志文件中提取特定格式的数据等。 替换和格式化在文本处理中用于替换特定模式的字符串或格式化文本例如将日期格式进行统一、删除不需要的空格等。 URL路由在web开发中用于定义和匹配URL路由规则实现页面的跳转和参数的提取。 语法分析在编译器和解释器中用于解析和处理特定语法和结构如正则表达式引擎本身就是一个语法解析器的实现。 日志分析用于分析和筛选大量日志数据中的特定模式和信息。 数据清洗在数据处理和清洗中使用正则表达式来识别和处理不规范的数据格式。 敏感词过滤用于在文本中过滤敏感词和不良内容。 字符串匹配用于查找字符串中是否包含特定的模式或关键字。