正則表達式不是Python中專有的,各種語言工具中都有這個正則表達式的體現。
正常情況下
但是想判斷一個字符串是否為郵箱格式,手機格式袁莉其他自己要求的格式時,這種==in就涜不能滿足要求了,它是一個格式定義,但是格式中的內容要滿足一定要求。
正則表達式是一種用于匹配和操作文本的強大工具,它是由一系列字符和特殊字符組成的模式,用于描述要匹配的文本模式。
正則表達式可以在文本中查找、替換、提取和驗證特定的模式。
正則表達式,又稱規則表達式,(Regular Expression,在代碼中常簡寫為regex、regexp或RE),是一種文本模式,包括普通字符(例如,a 到 z 之間的字母)和特殊字符(稱為"元字符"),是計算機科學的一個概念。正則表達式使用單個字符串來描述、匹配一系列匹配某個句法規則的字符串,通常被用來檢索、替換那些符合某個模式(規則)的文本。
許多程序設計語言都支持利用正則表達式進行字符串操作。
例如,在Perl中就內建了一個功能強大的正則表達式引擎。正則表達式這個概念最初是由Unix中的工具軟件(例如sed和grep)普及開來的,
后來在廣泛運用于Scala 、PHP、C# 、Java、C++ 、Objective-c、Perl 、Swift、VBScript 、Javascript、Ruby 以及Python等等。
正則表達式通??s寫成“regex”,單數有regexp、regex,復數有regexps、regexes、regexen。
在Python中需要通過正則表達式對字符串進?匹配的時候,可以使??個python自帶的模塊,名字為re。
正則表達式的大致匹配過程是:
正則表達式是一個特殊的字符序列,用于定義復雜字符串匹配功能的模式
要判斷一個字符串中包含123這幾個值是地可以有如下的寫法
寫法 1
>>> s='foo123bar'
>>> '123' in s
True
寫法2
>>> s='foo123bar'
>>> s.find('123')
3
>>> s.index('123')
3
假設您要確定字符串是否包含任何三個連續的十進制數字字符,而不是搜索像 這樣的固定子字符串,如字符串 '123''foo123bar''foo456bar''234baz''qux678'
主要關注一個函數 .re.search()
re.search(<regex>, <string>)
import re
re.search(...)
還剛才 查找123的例子,使用正則表達式如何實現
>>> s='foo123bar'
2
3>>> # One last reminder to import!
4>>> import re
5
6>>> re.search('123', s)
7<_sre.SRE_Match object; span=(3, 6), match='123'>
>>> if re.search('123', s):
... print('Found a match.')
... else:
... print('No match.')
...
Found a match.
這個時候正則表達式已經告訴你了查找到的字符串在哪里
>>> s[3:6]
'123'
元字符 | 說明 |
. | 代表任意字符 |
\ | |
[ ] | 匹配內部的任一字符或子表達式 |
[^] | 對字符集和取非 |
- | 定義一個區間 |
\ | 對下一字符取非(通常是普通變特殊,特殊變普通) |
* | 匹配前面的字符或者子表達式0次或多次 |
*? | 惰性匹配上一個 |
+ | 匹配前一個字符或子表達式一次或多次 |
+? | 惰性匹配上一個 |
? | 匹配前一個字符或子表達式0次或1次重復 |
{n} | 匹配前一個字符或子表達式 |
{m,n} | 匹配前一個字符或子表達式至少m次至多n次 |
{n,} | 匹配前一個字符或者子表達式至少n次 |
{n,}? | 前一個的惰性匹配 |
^ | 匹配字符串的開頭 |
\A | 匹配字符串開頭 |
$ | 匹配字符串結束 |
[\b] | 退格字符 |
\c | 匹配一個控制字符 |
\d | 匹配任意數字 |
\D | 匹配數字以外的字符 |
\t | 匹配制表符 |
\w | 匹配任意數字字母下劃線 |
\W | 不匹配數字字母下劃線 |
最簡單的例子,手機號13位校驗
>>> import re
>>> s="^\d{13}$"
>>> re.search(s,"11111")
>>> rs=re.search(s,"11111")
>>> rs
>>> re.search(s,"1234567890123")
<re.Match object; span=(0, 13), match='1234567890123'>
>>> re.search(s,"a234567890123")
>>>
判斷字符串中出現緊挨著的三個數字
>>> s='foo123bar'
>>> re.search('[0-9][0-9][0-9]', s)
<_sre.SRE_Match object; span=(3, 6), match='123'>
你也可以換一種辦法 [0-9]{3}:
>>> s='foo123bar'
>>> re.search('[0-9][0-9][0-9]', s)
<re.Match object; span=(3, 6), match='123'>
>>> re.search('[0-9]{3}', s)
<re.Match object; span=(3, 6), match='123'>
>>>
查找123出現在字符串中 1.3其實代理的就是123
>>> s='foo123bar'
>>> re.search('1.3', s)
<_sre.SRE_Match object; span=(3, 6), match='123'>
>>> s='foo13bar'
>>> print(re.search('1.3', s))
None
[a-z] 表示 a-z 26個小寫字母中的其中一個
[A-Z] 表示 A-Z 26個大寫字母中的其中一個
>>> re.search('[a-z]', 'FOObar')
<_sre.SRE_Match object; span=(3, 4), match='b'>
>>> re.search('[0-9][0-9]', 'foo123bar')
<_sre.SRE_Match object; span=(3, 5), match='12'>
>>> re.search('[0-9a-fA-f]', '--- a0 ---')
<_sre.SRE_Match object; span=(4, 5), match='a'>
匹配任何不是數字的字符:^[^0-9]
>>> re.search('[^0-9]', '12345foo')
<_sre.SRE_Match object; span=(5, 6), match='f'>
如果字符出現在字符類中,但不是第一個字符,則它沒有特殊含義,并且與文本字符匹配:
>>> re.search('[#:^]', 'foo^bar:baz#qux')
<_sre.SRE_Match object; span=(3, 4), match='^'>
間斷性匹配例如座機號碼有一個 -
>>> re.search('[-abc]', '123-456')
<_sre.SRE_Match object; span=(3, 4), match='-'>
>>> re.search('[abc-]', '123-456')
<_sre.SRE_Match object; span=(3, 4), match='-'>
>>> re.search('[ab\-c]', '123-456')
<_sre.SRE_Match object; span=(3, 4), match='-'>
英文的 . 字符匹配除換行符之外的任何單個字符:.
>>> re.search('foo.bar', 'fooxbar')
<_sre.SRE_Match object; span=(0, 7), match='fooxbar'>
>>> print(re.search('foo.bar', 'foobar'))
None
>>> print(re.search('foo.bar', 'foo\nbar'))
None
\w匹配任何字母數字單詞字符。
單詞字符是大寫和小寫字母、數字和下劃線 () 字符,
因此本質上是:\w 等價于[a-zA-Z0-9_]:
\W是與\w相反
[^a-zA-Z0-9_]
>>> re.search('\W', 'a_1*3Qb')
<_sre.SRE_Match object; span=(3, 4), match='*'>
>>> re.search('[^a-zA-Z0-9_]', 'a_1*3Qb')
<_sre.SRE_Match object; span=(3, 4), match='*'>
\d 匹配任何十進制數字字符 等價于 [0-9]
\D 匹配非數字 [^0-9]
>>> re.search('\d', 'abc4def')
<_sre.SRE_Match object; span=(3, 4), match='4'>
>>> re.search('\D', '234Q678')
<_sre.SRE_Match object; span=(3, 4), match='Q'>
\s 匹配任何空格字符:
\S 是 的反義詞。它匹配任何非空格字符:\s
>>> re.search('\s', 'foo\nbar baz')
<_sre.SRE_Match object; span=(3, 4), match='\n'>
>>> re.search('\S', ' \n foo \n ')
<_sre.SRE_Match object; span=(4, 5), match='f'>
下一篇文章介紹
網絡圖片
頭條創作挑戰賽#
#醉魚Java#
代碼地址: https://github.com/zuiyu-main/EncryptDemo
在個別特殊領域中,數據的安全問題是非常的重要的,所以需要數據庫存儲的數據是需要加密存儲的。所以也就引申出來本文這個問題,加密之后的密文,還能模糊檢索嗎,如果能檢查,如何做模糊檢索呢?
現在的系統設計中,常見的加密字段有、密碼、身份證號、手機號、住址信息、銀行卡、信用卡以及個別行業的敏感信息。這些信息對加密的要求也不一樣,對于密碼來說,一般使用不可逆的加密算法就可以,一般不會用到檢索。但是對于身份證號或者個別領域中的中文信息,我們是需要支持密文模糊匹配的,下面我們就來看看有哪些實現方式。
本來主要講兩種常規的簡單加密做法,主要目標為能實現密文的模糊查詢。下面來跟我看第一種。
常規加密的密文檢索功能根據4位英文字符(半角),2個中文字符(全角)作為一個檢索條件,將一個字段拆分為多個字段。
比如:zuiyu123
使用4個字符為一組的加密方式。
第一組 zuiy,第二組uiyu,第三組iyu1,第四組yu12,第五組u123...如果字符串很長,依次類推下去。
如果需要檢索所有包含檢索條件 uiyu 的數據,加密字符后通過 key like ‘%加密uiyu的密文%’查詢。
所以這種實現方式就會有一種問題就是,隨著加密字符串的增加,密文也會變的越大,所以一般用此處方式需要注意數據庫中的字段長度限制。
需要注意的是,使用此處方式有一定的限制:
1、支持模糊檢索加密,但是加密的密文隨原文長度增長。
2、支持的模糊檢索條件必須大于等于4個英文數字或者2個漢字,不支持短的查詢(自定義該局限性,業界常用的就是4個英文數字或者2個漢字,再短的長度不建議支持,因為分詞組合會增多從而導致存儲的成本增加,反而安全性降低。)。
3、返回的列表不是很精確,需要二次篩選,先解密在進一步篩選。
字符串拆分的代碼如下:
protected List<String> loopEncryptString(String input, int chunkSize) {
int length=input.length();
List<String> strList=new LinkedList<>();
for (int i=0; i < length; i++) {
StringBuilder chunkBuilder=new StringBuilder();
for (int j=0; j < chunkSize; j++) {
int index=(i + j) % length;
chunkBuilder.append(input.charAt(index));
}
strList.add(chunkBuilder.toString());
log.info("第 {} 組:[{}]",i+1,chunkBuilder);
// 如果到了最后一個分組,則不再循環第一個字符
if (i + chunkSize >=length) {
break;
}
}
log.info("分詞結果:[{}]",strList);
return strList;
}
對于上述文本zuiyu123分詞效果如下
下面來看下中文的分詞效果:
檢索一下,只要我們使用的是包含上述分詞結果的條件我們就可以檢索的到。
比如我們檢索個蛋白質
search result:[[{ID=8dac4d97-f05f-472e-94b2-02828aa235d6, CONTENT=ELYJBkZbfiVaJgTdlgglDg==UYwxxmEMQ9hq1jOax+r5rg==WwCBtglEf6clcWajP9sK+A==4sEGCqZ4P8Osr0dW84zFEA==c2AZejHeUp/5gpPkexfNcg==pvh/TcZRO4zwD+kwbE9lHw==1g30dxyz7z+8TQq+8jYH1A==AsWZOeiprypfrzSK3FtOuw==01vpoSuCXOpKCgcPsNlXyQ==79BPmIhSwMaA7hjN3ENDxA==}]]
可以看到,上述的content字段的內容長度非常的長,所以我們要注意數據庫字段長度限制。
除了上面這個方式外,發散一下思維,如果你用過 Elasticsearch 的話,會不會有點想法呢?
因為在中文的場景中,中文既然要分詞,選擇專業的分詞器應該是更合理的啊,所以我們可以使用???
對的,你沒猜錯,既然是要分詞,對于特殊的中文業務場景,直接使用 Elasticsearch 的分詞器分詞不就好了嗎,然后再用 Elasticsearch 的強大檢索能力,不就可以滿足我們的模糊檢索需求了嗎,想到就去做,下面就跟著我一起來看下如果用 Elasticsearch 的分詞實現密文模糊檢索。
使用分詞器分詞進行密文檢索的原理:
1、使用 Elasticsearch 自帶的正則分詞器對加密后的密文進行分詞。
2、檢索時使用 Elasticsearch 的match進行檢索。
本文演示使用AES進行加解密,所以分詞器我就直接使用正則匹配,將密文中的內容按照==進行拆分。
下面我們一起進入代碼時間,跟隨著我的腳本來看看分詞密文檢索是什么樣的。
也歡迎你來實操體驗一下,有什么問題歡迎評論區留言告訴我,也可以關注《醉魚Java》,私信我。
如果使用 7+、8+ 的需要修改為對應的版本。mappings 中的 _doc
put 127.0.0.1:9200/encrypt
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"tokenizer": "my_tokenizer"
}
},
"tokenizer": {
"my_tokenizer": {
"type": "pattern",
"pattern": "=="
}
}
}
},
"mappings": {
"_doc": {
"properties": {
"content": {
"type": "text"
}
}
}
}
}
其實不難發現,我們使用 AES 加密,就是對分詞之后的每個詞語進行加密,然后組成一個新的字符串。
還是上面那句話魚肉的蛋白質含量真的高,我們看一下分詞結果。
所以我們按照==拆分之后,檢索式再通過加密之后的密文進行檢索,也就相當于分詞檢索了。
檢索結果如下:
search result:[{"hits":[{"_index":"encrypt","_type":"_doc","_source":{"content":"ELYJBkZbfiVaJgTdlgglDg==9hF4g5NErtZNS9qFJGYeZA==uH9W7jvdoLIKq5gOpFjhWg==4sEGCqZ4P8Osr0dW84zFEA==c2AZejHeUp/5gpPkexfNcg==1g30dxyz7z+8TQq+8jYH1A==01vpoSuCXOpKCgcPsNlXyQ==kIzJL/y/pnUbkZGjIkz4tw=="},"_id":"1713343285459","_score":2.8951092}],"total":1,"max_score":2.8951092}]
密文的模糊查詢就是以空間成本換取的。相比于存儲原文,密文比原文增長了好幾倍。
所以根據你的業務場景,選擇一個合適的加密算法才是最優解。
https://open.taobao.com/docV3.htm?docId=106213&docType=1
https://ningyu1.github.io/20201230/encrypted-data-fuzzy-query.html
正在參加一場關鍵的技術面試,對面坐著一位經驗豐富的面試官。他微笑著提出一個問題:“能否實現一個模糊搜索功能,用JavaScript來寫?”這個問題看似簡單,但它考驗的不僅是你的編程技巧,還考察你在實際場景中解決問題的能力和思維方式。
為了幫助你在這種場景下表現出色,我將帶你一起實現一個簡單但有效的模糊搜索功能,并詳細解釋其中的關鍵點。掌握這項技術,不僅能讓你在面試中脫穎而出,還能在實際工作中為用戶提供更好的搜索體驗。
面試官首先解釋了“模糊搜索”的概念。模糊搜索是一種技術,它允許你在文本中找到與用戶輸入接近的結果,即使輸入中存在小的錯誤或字符順序不完全匹配。這在處理用戶可能拼錯字或鍵入字符順序不一致時特別有用。
接下來,面試官給出了一組字符串數組,要求你在這個數組中實現模糊搜索。你開始思考,決定使用“滑動窗口”技術來解決這個問題。你在面試官的注視下開始編寫代碼:
const arr=[
"JavaScript",
"TypeScript",
"Python",
"Java",
"Ruby on Rails",
"ReactJS",
"Angular",
"Vue.js",
"Node.js",
"Django",
"Spring Boot",
"Flask",
"Express.js",
];
面試官點頭示意你繼續。你明白,要實現這個功能,關鍵在于編寫一個能逐字符檢查匹配的函數。于是你寫下了如下代碼:
const fuzzySearch=(str, query)=>
{
str=str.toLowerCase(); // 將字符串轉換為小寫,確保不區分大小寫
query=query.toLowerCase(); // 同樣轉換查詢字符串
let i=0, lastSearched=-1, current=query[i];
while (current)
{
// 使用 !~ 來判斷當前字符是否在目標字符串中按順序出現
if (!~(lastSearched=str.indexOf(current, lastSearched + 1)))
{
return false; // 如果沒找到,則返回 false
};
current=query[++i]; // 查找下一個字符
}
return true; // 如果所有字符都找到,則返回 true
};
在編寫代碼的過程中,你停下來向面試官解釋道,滑動窗口是一種常見的算法技巧,特別適用于字符串和數組的處理問題?;瑒哟翱诘暮诵乃枷胧窃跀祿Y構內保持一個“窗口”,逐步滑動窗口的位置進行檢查或計算。
在 fuzzySearch 函數中,滑動窗口的概念被用來逐字符地在目標字符串中查找查詢字符串中的字符。每次找到一個字符后,搜索的起始位置會向前移動,確保后續字符的匹配不會回到已經匹配過的位置,從而保證字符匹配的順序性。
接下來,你向面試官逐步解釋了每一行代碼的邏輯:
面試官顯然對你的解釋感到滿意,你繼續編寫用于過濾整個數組的函數:
const search=function(arr, query)
{
return arr.filter((e)=> fuzzySearch(e, query)); // 使用 fuzzySearch 過濾數組
};
然后你運行了代碼,并向面試官展示了模糊搜索的效果:
console.log(search(arr, 'Java')); // 輸出 [ 'JavaScript', 'Java' ]
面試官看了輸出結果,點頭稱贊。他認可了你如何通過這個方法在字符串數組中實現了模糊搜索,并展示了實際效果。
在這個面試場景中,你不僅展示了扎實的JavaScript基礎,還通過簡潔而高效的代碼,解決了一個實際問題。你的表現讓面試官印象深刻,這也證明了你在面對挑戰時的思維方式和解決問題的能力。
面試不僅是展示你掌握多少知識,更是展示你解決問題的能力和思維方式。愿你在每一場面試中都能從容應對,拿下心儀的Offer!
*請認真填寫需求信息,我們會在24小時內與您取得聯系。