• 第二十二 查询、检索、搜索


    查询在计算机中十分广泛的应用。

    • 在字符串或者文本文件中查询关键字,模式匹配,正则表达式。
    • 在数组、树、哈希表等数据结构中查询指定数据
    • 在数据库中查询
    • 在海量非结构文件中查询
    • 搜索引擎

    模式匹配

    模式匹配是数据结构中字符串的一种基本运算,给定一个子串,要求在某个字符串中找出与该子串相同的所有子串,这就是模式匹配。

    模式匹配

    经典问题:strStr()

    DFA算法

     

    1. use std::collections::BTreeSet;
    2. use std::collections::HashMap;
    3. use std::fs::File;
    4. use std::io::prelude::*;
    5. use std::io::BufReader;
    6. use std::str::Chars;
    7. /// 敏感词检测DFA算法(Rust实现,参考Java版实现 https://www.cnblogs.com/shihaiming/p/7048379.html)
    8. /// 由于语言方面的限制,具体实现与Java有一定的差异。
    9. ///
    10. lazy_static! {
    11. static ref SENSITIVE_WORD_MAP: HashMap<char, SensitiveWordMap> = {
    12. let set = read_sensitive_word_file();
    13. build_sensitive_word_map(set)
    14. };
    15. }
    16. pub enum MatchType {
    17. MinMatchType, //最小匹配规则
    18. MaxMatchType, //最大匹配规则
    19. }
    20. #[derive(Debug)]
    21. struct SensitiveWordMap {
    22. word: char,
    23. is_end: char,
    24. word_map: Optionchar, Box>>,
    25. }
    26. /// 替换敏感字字符
    27. /// # Examples
    28. /// ```
    29. /// let result = rust_by_example::dfa::replace_sensitive_word("信用卡之家", &MatchType::MinMatchType, '*')
    30. /// assert_eq!(result,"**卡之家");
    31. /// ```
    32. pub fn replace_sensitive_word(txt: &str, match_type: &MatchType, replace_char: char) -> String {
    33. let set: BTreeSet<String> = find_sensitive_word(txt, match_type);
    34. let mut replace_str = String::from(txt);
    35. for word in set {
    36. let len = word.chars().count();
    37. let replace_chars: String = vec![replace_char; len].iter().collect();
    38. replace_str = replace_str.replace(word.as_str(), &replace_chars);
    39. }
    40. replace_str
    41. }
    42. /// 判断文字是否包含敏感字符
    43. ///
    44. pub fn is_contains_sensitive_word(txt: &str, match_type: &MatchType) -> bool {
    45. let mut is_contains = false;
    46. let len = txt.chars().count();
    47. let txt_vec: Vec<char> = txt.chars().collect();
    48. let mut i = 0;
    49. while i < len {
    50. let length = check_sensitive_word(txt, i, match_type);
    51. if length > 0 {
    52. is_contains = true;
    53. break;
    54. }
    55. i += 1;
    56. }
    57. is_contains
    58. }
    59. /// 获取文字中的敏感词
    60. ///
    61. pub fn find_sensitive_word(txt: &str, match_type: &MatchType) -> BTreeSet<String> {
    62. let mut sensitive_word_set = BTreeSet::<String>::new();
    63. let len = txt.chars().count();
    64. let txt_vec: Vec<char> = txt.chars().collect();
    65. let mut i = 0;
    66. while i < len {
    67. let length = check_sensitive_word(txt, i, match_type);
    68. if length > 0 {
    69. //存在,加入list中
    70. sensitive_word_set.insert(txt_vec[i..i + length].iter().collect());
    71. i += length - 1; //减1的原因,是因为循环会自增
    72. }
    73. i += 1;
    74. }
    75. sensitive_word_set
    76. }
    77. /// 查文字中是否包含检敏感字符,如果存在,则返回敏感词字符的长度,不存在返回0
    78. ///
    79. fn check_sensitive_word(txt: &str, begin_index: usize, match_type: &MatchType) -> usize {
    80. let mut match_flag = 0;
    81. let mut last_match_length = 0;
    82. let mut word: char;
    83. let txt_vec: Vec<char> = txt.chars().collect();
    84. let len = txt.len();
    85. if let Some(word) = &txt_vec.get(begin_index) {
    86. if let Some(swm) = SENSITIVE_WORD_MAP.get(word) {
    87. match_flag += 1;
    88. if (*swm).is_end == '1' {
    89. last_match_length = match_flag;
    90. match match_type {
    91. MatchType::MinMatchType => {
    92. return last_match_length;
    93. }
    94. MatchType::MaxMatchType => (),
    95. }
    96. }
    97. //递归查找
    98. let mut j = begin_index + 1;
    99. recursive_find_map(
    100. swm,
    101. &txt_vec,
    102. &mut j,
    103. &mut match_flag,
    104. &mut last_match_length,
    105. match_type,
    106. );
    107. }
    108. }
    109. last_match_length
    110. }
    111. /// 递归查找map
    112. ///
    113. fn recursive_find_map(
    114. swm: &SensitiveWordMap,
    115. txt_vec: &[char],
    116. i: &mut usize,
    117. match_flag: &mut usize,
    118. last_match_length: &mut usize,
    119. match_type: &MatchType,
    120. ) {
    121. if let Some(word) = txt_vec.get(*i) {
    122. if let Some(wm) = &swm.word_map {
    123. if let Some(next_swm) = wm.get(word) {
    124. *match_flag += 1;
    125. if swm.is_end == '1' {
    126. *last_match_length = *match_flag;
    127. match match_type {
    128. MatchType::MinMatchType => {
    129. return;
    130. }
    131. MatchType::MaxMatchType => (),
    132. }
    133. }
    134. if next_swm.is_end == '1' {
    135. *last_match_length = *match_flag;
    136. match match_type {
    137. MatchType::MinMatchType => {
    138. return;
    139. }
    140. MatchType::MaxMatchType => (),
    141. }
    142. }
    143. if let Some(nwm) = &next_swm.word_map {
    144. if nwm.is_empty() {
    145. *last_match_length = *match_flag;
    146. match match_type {
    147. MatchType::MinMatchType => {
    148. return;
    149. }
    150. MatchType::MaxMatchType => (),
    151. }
    152. }
    153. }
    154. *i += 1;
    155. recursive_find_map(
    156. next_swm,
    157. txt_vec,
    158. i,
    159. match_flag,
    160. last_match_length,
    161. match_type,
    162. );
    163. }
    164. }
    165. }
    166. }
    167. /// 递归地修改map
    168. fn recursive_build_map(map: &mut SensitiveWordMap, chars: &mut Chars, count: &mut usize) {
    169. if let Some(ch) = chars.next() {
    170. *count -= 1;
    171. if let Some(now_map) = map.word_map.as_mut() {
    172. // let contains_key = now_map.contains_key(&ch);
    173. if let std::collections::hash_map::Entry::Vacant(e) = now_map.entry(ch) {
    174. let mut is_end = if *count == 0 { '1' } else { '0' };
    175. let mut swm = SensitiveWordMap {
    176. word: ch,
    177. is_end,
    178. word_map: Some(HashMap::<char, Box>::new()),
    179. };
    180. now_map.insert(ch, Box::new(swm));
    181. if let Some(m) = now_map.get_mut(&ch) {
    182. recursive_build_map(&mut *m, &mut *chars, count);
    183. }
    184. } else if let Some(m) = now_map.get_mut(&ch) {
    185. recursive_build_map(&mut *m, &mut *chars, count);
    186. }
    187. }
    188. }
    189. }
    190. /// 读取敏感词库,将敏感词放入HashMap中,构建一个DFA算法模型
    191. /// {
    192. /// '信': SensitiveWordMap {
    193. /// word: '信',
    194. /// is_end: '0',
    195. /// word_map: Some({
    196. /// '用': SensitiveWordMap {
    197. /// word: '用',
    198. /// is_end: '0',
    199. /// word_map: Some({
    200. /// '卡': SensitiveWordMap {
    201. /// word: '卡',
    202. /// is_end: '0',
    203. /// word_map: Some({
    204. /// '套': SensitiveWordMap {
    205. /// word: '套',
    206. /// is_end: '0',
    207. /// word_map: Some({
    208. /// '现': SensitiveWordMap {
    209. /// word: '现',
    210. /// is_end: '1',
    211. /// word_map: Som e({})
    212. /// }
    213. /// })
    214. /// },
    215. /// '代': SensitiveWordMap {
    216. /// word: '代',
    217. /// is_end: '0',
    218. /// word_map: Some({
    219. /// '付': SensitiveWordMap {
    220. /// word: '付',
    221. /// is_end: '1',
    222. /// word_map: Some({})
    223. /// },
    224. /// '还': SensitiveWordMap {
    225. /// word: '还',
    226. /// is_end: '1',
    227. /// word_map: Some({})
    228. /// }
    229. /// })
    230. /// }
    231. /// })
    232. /// }
    233. /// })
    234. /// }
    235. /// })
    236. /// }
    237. ///
    238. fn build_sensitive_word_map(set: BTreeSet<String>) -> HashMap<char, SensitiveWordMap> {
    239. let mut sensitive_word_map = HashMap::<char, SensitiveWordMap>::new();
    240. let mut iterator = set.iter();
    241. for key in iterator {
    242. let len = key.chars().count();
    243. let mut count = len;
    244. let mut key_chars = key.chars();
    245. //读取每行的首个字符
    246. if let Some(first_char) = key_chars.next() {
    247. count -= 1;
    248. if let Some(word_map) = sensitive_word_map.get_mut(&first_char) {
    249. //读取下一个字符
    250. recursive_build_map(&mut *word_map, &mut key_chars, &mut count);
    251. } else {
    252. let mut is_end = if len == 1 { '1' } else { '0' };
    253. let mut now_map = SensitiveWordMap {
    254. word: first_char,
    255. is_end,
    256. word_map: Some(HashMap::<char, Box>::new()),
    257. };
    258. sensitive_word_map.insert(first_char, now_map);
    259. if let Some(now_map) = sensitive_word_map.get_mut(&first_char) {
    260. recursive_build_map(&mut *now_map, &mut key_chars, &mut count);
    261. }
    262. }
    263. }
    264. }
    265. sensitive_word_map
    266. }
    267. /// 读取敏感词库中的内容,将内容添加到set集合中
    268. fn read_sensitive_word_file() -> BTreeSet<String> {
    269. let mut set = BTreeSet::<String>::new();
    270. match File::open("sensitive-words.txt") {
    271. Ok(f) => {
    272. let reader = BufReader::new(f);
    273. let lines = reader.lines();
    274. for line in lines.map(|x| x.unwrap()) {
    275. println!("{}", line);
    276. set.insert(line);
    277. }
    278. }
    279. Err(e) => panic!("can't open this file :{}", e),
    280. }
    281. set
    282. }
    283. #[test]
    284. fn read_file() {
    285. let str_vec = vec![
    286. "花呗信用卡代还OK套现",
    287. "套花呗分期代付",
    288. "马上套现信用卡",
    289. "期货套利",
    290. "空手套白狼",
    291. "守信用卡脖子",
    292. "坚定信心,同舟共济,科学防治,精准施策",
    293. "D+1还是T+1秒到结算免结算费",
    294. ];
    295. println!("find_sensitive_word MaxMatchType......");
    296. for str in &str_vec {
    297. let set = find_sensitive_word(str, &MatchType::MaxMatchType);
    298. println!("{} --> {:?}", str, set);
    299. }
    300. println!("find_sensitive_word MinMatchType......");
    301. for str in &str_vec {
    302. let set = find_sensitive_word(str, &MatchType::MinMatchType);
    303. println!("{} --> {:?}", str, set);
    304. }
    305. println!("is_contains_sensitive_word......");
    306. for str in &str_vec {
    307. let is_contains = is_contains_sensitive_word(str, &MatchType::MinMatchType);
    308. println!("{} is contains sensitive words : {}", str, is_contains);
    309. }
    310. println!("replace_sensitive_word......");
    311. for str in &str_vec {
    312. let replace_str = replace_sensitive_word(str, &MatchType::MinMatchType, '*');
    313. println!("{} --> {}", str, replace_str);
    314. }
    315. let result = replace_sensitive_word("信用卡之家", &MatchType::MinMatchType, '*');
    316. assert_eq!(result, "**卡之家");
    317. }
    318. #[test]
    319. fn sub_str() {
    320. //实现类似Java String.substring()的功能,注意并不是适用于所有的字符。
    321. let str = String::from("hello world");
    322. let char_vec: Vec<char> = str.chars().collect();
    323. let sub_str: String = char_vec[0..5].iter().collect();
    324. println!("sub_str:{}", sub_str);
    325. //不能使用上述代码进行截取子字符串的字符
    326. for c in "नमस्ते".chars() {
    327. println!("{}", c);
    328. }
    329. }
    330. #[test]
    331. fn set_iter() {
    332. let mut b_tree_set = BTreeSet::<String>::new();
    333. b_tree_set.insert(String::from("A"));
    334. b_tree_set.insert(String::from("B"));
    335. b_tree_set.insert(String::from("C"));
    336. b_tree_set.insert(String::from("D"));
    337. b_tree_set.insert(String::from("E"));
    338. for val in &b_tree_set {
    339. println!("{}", val);
    340. }
    341. let rm_key = String::from("C");
    342. b_tree_set.remove(&rm_key);
    343. println!("b_tree_set has {} items", b_tree_set.len());
    344. println!("using VSCode coding rust program is greate");
    345. }

    KMP匹配算法

    1. /// https://github.com/TheAlgorithms/Rust/blob/master/src/string/knuth_morris_pratt.rs
    2. pub fn knuth_morris_pratt(st: String, pat: String) -> Vec<usize> {
    3. if st.is_empty() || pat.is_empty() {
    4. return vec![];
    5. }
    6. let string = st.into_bytes();
    7. let pattern = pat.into_bytes();
    8. // build the partial match table
    9. let mut partial = vec![0];
    10. for i in 1..pattern.len() {
    11. let mut j = partial[i - 1];
    12. while j > 0 && pattern[j] != pattern[i] {
    13. j = partial[j - 1];
    14. }
    15. partial.push(if pattern[j] == pattern[i] { j + 1 } else { j });
    16. }
    17. // and read 'string' to find 'pattern'
    18. let mut ret = vec![];
    19. let mut j = 0;
    20. for (i, &c) in string.iter().enumerate() {
    21. while j > 0 && c != pattern[j] {
    22. j = partial[j - 1];
    23. }
    24. if c == pattern[j] {
    25. j += 1;
    26. }
    27. if j == pattern.len() {
    28. ret.push(i + 1 - j);
    29. j = partial[j - 1];
    30. }
    31. }
    32. ret
    33. }

     

    正则表达式

    驼峰命名转为蛇形命名
     echo "camelToSnakeName" | sed 's/\([a-z0-9]\)\([A-Z]\)/\1_\2/g' | tr '[:lower:]' '[:upper:]'
    1. use itertools::Itertools;
    2. use regex::Captures;
    3. use regex::NoExpand;
    4. use regex::Regex;
    5. use std::collections::HashMap;
    6. lazy_static! {
    7. //驼峰命名
    8. static ref CAMEL_TO_SNAKE1: Regex = Regex::new(r"(.)([A-Z][a-z]+)").unwrap();
    9. static ref CAMEL_TO_SNAKE2: Regex = Regex::new(r"([a-z0-9])([A-Z])").unwrap();
    10. }
    11. /// 驼峰命名转为蛇形命名
    12. pub fn camel_to_snake(origin: &str) -> String {
    13. let result0 = CAMEL_TO_SNAKE1.replace_all(origin, |caps: &Captures| {
    14. format!("{}_{}", &caps[1], &caps[2])
    15. });
    16. let result = CAMEL_TO_SNAKE2.replace_all(&result0, |caps: &Captures| {
    17. format!("{}_{}", &caps[1], &caps[2])
    18. });
    19. result.to_uppercase()
    20. }
    21. /// 驼峰命名转为帕斯卡命名法
    22. pub fn snake_to_pascal(origin: &str) -> String {
    23. // origin.split('_');
    24. let word_vec: Vec<&str> = origin.split('_').collect();
    25. //每个单词首字母大写
    26. word_vec
    27. .iter()
    28. .map(|&word| {
    29. let mut chars = word.chars();
    30. match chars.next() {
    31. Some(ch) => ch.to_uppercase().collect::<String>() + chars.as_str(),
    32. None => String::new(),
    33. }
    34. })
    35. .join("")
    36. }
    37. /// 蛇形命名转驼峰命名
    38. pub fn snake_to_camel(s: &str) -> String {
    39. let result = snake_to_pascal(s);
    40. let mut chars = result.chars();
    41. match chars.next() {
    42. Some(ch) => ch.to_lowercase().collect::<String>() + chars.as_str(),
    43. None => String::new(),
    44. }
    45. }
    46. #[test]
    47. fn fileds() {
    48. let fileds_vec = vec!["FalconHeavyRocket", "HTTPResponseCodeXYZ"];
    49. fileds_vec.iter().for_each(|&filed| {
    50. let result = camel_to_snake(filed);
    51. println!("{}", result);
    52. });
    53. let columns_vec = vec!["falcon_heavy_rocket", "http_response_code_xyz"];
    54. columns_vec.iter().for_each(|&column| {
    55. let result = snake_to_pascal(column);
    56. println!("{}", result);
    57. });
    58. let columns_vec = vec!["falcon_heavy_rocket", "http_response_code_xyz"];
    59. columns_vec.iter().for_each(|&column| {
    60. let result = snake_to_camel(column);
    61. println!("{}", result);
    62. });
    63. }

     

     

    更多正则表达式示例代码

    经典查询算法

    查询算法:二分查找、哈希查找、二叉树查找、、

    二分查找

    1. /// 力扣(704. 二分查找) https://leetcode-cn.com/problems/binary-search/
    2. pub fn search(nums: Vec<i32>, target: i32) -> i32 {
    3. // target在[left,right]中查找
    4. let len = nums.len();
    5. let mut left = 0;
    6. let mut right = len - 1;
    7. let mut pivot;
    8. while left <= right {
    9. pivot = left + (right - left) / 2;
    10. // 注意usize的范围和nums的下标范围
    11. if nums[pivot] == target {
    12. return pivot as i32;
    13. }
    14. if target < nums[pivot] {
    15. if pivot == 0 {
    16. break;
    17. }
    18. right = pivot - 1;
    19. } else {
    20. if pivot == len - 1 {
    21. break;
    22. }
    23. left = pivot + 1;
    24. }
    25. }
    26. -1
    27. }

     

    二叉树查找

    1. //! 二叉树
    2. //! https://leetcode-cn.com/tag/binary-tree/problemset/
    3. use std::cell::RefCell;
    4. use std::cmp::max;
    5. use std::collections::VecDeque;
    6. use std::rc::Rc;
    7. #[derive(Debug, PartialEq, Eq)]
    8. pub struct TreeNode {
    9. pub val: i32,
    10. pub left: Option>>,
    11. pub right: Option>>,
    12. }
    13. impl TreeNode {
    14. #[inline]
    15. pub fn new(val: i32) -> Self {
    16. TreeNode {
    17. val,
    18. left: None,
    19. right: None,
    20. }
    21. }
    22. /// 树的深度:也称为树的高度,树中所有结点的层次最大值称为树的深度
    23. pub fn get_height(root: &Option>>) -> i32 {
    24. fn dfs(root: &Option>>) -> i32 {
    25. match root {
    26. None => 0,
    27. Some(node) => {
    28. let node = node.borrow_mut();
    29. 1 + max(dfs(&node.left), dfs(&node.right))
    30. }
    31. }
    32. }
    33. dfs(root)
    34. }
    35. }
    36. /// 230. 二叉搜索树中第K小的元素 https://leetcode.cn/problems/kth-smallest-element-in-a-bst/
    37. pub fn kth_smallest(root: Option>>, k: i32) -> i32 {
    38. fn traverse(root: Option>>, counter: &mut Vec<i32>) {
    39. if let Some(node) = root {
    40. traverse(node.borrow_mut().left.take(), counter);
    41. counter.push(node.borrow_mut().val);
    42. traverse(node.borrow_mut().right.take(), counter);
    43. }
    44. }
    45. let mut counter = vec![];
    46. traverse(root, &mut counter);
    47. counter[(k - 1) as usize]
    48. }

     



     

  • 相关阅读:
    vue模板语法上集->插值,指令,过滤器,计算属性&监听属性,vue购物车
    前端技能树初体验
    网页数据抓取-网页实时数据抓取软件
    “华为杯”研究生数学建模竞赛2019年-【华为杯】F题:智能飞行器航迹规划模型(下)(附优秀论文及Pyhton代码实现)
    【Pandas】Python数据分析活用Pandas库学习笔记(三)
    Java网络编程1
    浅谈JS中null的江湖地位
    杭电oj1009(贪心算法)
    Unity-huatuo热更新调研
    【Lua 入门基础篇(三)】流程控制&函数&ipairs&pairs
  • 原文地址:https://blog.csdn.net/smallswan/article/details/136584621