Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
正則表達(dá)式不是Python中專有的,各種語言工具中都有這個(gè)正則表達(dá)式的體現(xiàn)。
正常情況下
但是想判斷一個(gè)字符串是否為郵箱格式,手機(jī)格式袁莉其他自己要求的格式時(shí),這種==in就涜不能滿足要求了,它是一個(gè)格式定義,但是格式中的內(nèi)容要滿足一定要求。
正則表達(dá)式是一種用于匹配和操作文本的強(qiáng)大工具,它是由一系列字符和特殊字符組成的模式,用于描述要匹配的文本模式。
正則表達(dá)式可以在文本中查找、替換、提取和驗(yàn)證特定的模式。
正則表達(dá)式,又稱規(guī)則表達(dá)式,(Regular Expression,在代碼中常簡寫為regex、regexp或RE),是一種文本模式,包括普通字符(例如,a 到 z 之間的字母)和特殊字符(稱為"元字符"),是計(jì)算機(jī)科學(xué)的一個(gè)概念。正則表達(dá)式使用單個(gè)字符串來描述、匹配一系列匹配某個(gè)句法規(guī)則的字符串,通常被用來檢索、替換那些符合某個(gè)模式(規(guī)則)的文本。
許多程序設(shè)計(jì)語言都支持利用正則表達(dá)式進(jìn)行字符串操作。
例如,在Perl中就內(nèi)建了一個(gè)功能強(qiáng)大的正則表達(dá)式引擎。正則表達(dá)式這個(gè)概念最初是由Unix中的工具軟件(例如sed和grep)普及開來的,
后來在廣泛運(yùn)用于Scala 、PHP、C# 、Java、C++ 、Objective-c、Perl 、Swift、VBScript 、Javascript、Ruby 以及Python等等。
正則表達(dá)式通常縮寫成“regex”,單數(shù)有regexp、regex,復(fù)數(shù)有regexps、regexes、regexen。
在Python中需要通過正則表達(dá)式對字符串進(jìn)?匹配的時(shí)候,可以使??個(gè)python自帶的模塊,名字為re。
正則表達(dá)式的大致匹配過程是:
正則表達(dá)式是一個(gè)特殊的字符序列,用于定義復(fù)雜字符串匹配功能的模式
要判斷一個(gè)字符串中包含123這幾個(gè)值是地可以有如下的寫法
寫法 1
>>> s='foo123bar'
>>> '123' in s
True
寫法2
>>> s='foo123bar'
>>> s.find('123')
3
>>> s.index('123')
3
假設(shè)您要確定字符串是否包含任何三個(gè)連續(xù)的十進(jìn)制數(shù)字字符,而不是搜索像 這樣的固定子字符串,如字符串 '123''foo123bar''foo456bar''234baz''qux678'
主要關(guān)注一個(gè)函數(shù) .re.search()
re.search(<regex>, <string>)
import re
re.search(...)
還剛才 查找123的例子,使用正則表達(dá)式如何實(shí)現(xiàn)
>>> 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.
這個(gè)時(shí)候正則表達(dá)式已經(jīng)告訴你了查找到的字符串在哪里
>>> s[3:6]
'123'
元字符 | 說明 |
. | 代表任意字符 |
\ | |
[ ] | 匹配內(nèi)部的任一字符或子表達(dá)式 |
[^] | 對字符集和取非 |
- | 定義一個(gè)區(qū)間 |
\ | 對下一字符取非(通常是普通變特殊,特殊變普通) |
* | 匹配前面的字符或者子表達(dá)式0次或多次 |
*? | 惰性匹配上一個(gè) |
+ | 匹配前一個(gè)字符或子表達(dá)式一次或多次 |
+? | 惰性匹配上一個(gè) |
? | 匹配前一個(gè)字符或子表達(dá)式0次或1次重復(fù) |
{n} | 匹配前一個(gè)字符或子表達(dá)式 |
{m,n} | 匹配前一個(gè)字符或子表達(dá)式至少m次至多n次 |
{n,} | 匹配前一個(gè)字符或者子表達(dá)式至少n次 |
{n,}? | 前一個(gè)的惰性匹配 |
^ | 匹配字符串的開頭 |
\A | 匹配字符串開頭 |
$ | 匹配字符串結(jié)束 |
[\b] | 退格字符 |
\c | 匹配一個(gè)控制字符 |
\d | 匹配任意數(shù)字 |
\D | 匹配數(shù)字以外的字符 |
\t | 匹配制表符 |
\w | 匹配任意數(shù)字字母下劃線 |
\W | 不匹配數(shù)字字母下劃線 |
最簡單的例子,手機(jī)號13位校驗(yàn)
>>> 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")
>>>
判斷字符串中出現(xiàn)緊挨著的三個(gè)數(shù)字
>>> 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出現(xiàn)在字符串中 1.3其實(shí)代理的就是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個(gè)小寫字母中的其中一個(gè)
[A-Z] 表示 A-Z 26個(gè)大寫字母中的其中一個(gè)
>>> 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'>
匹配任何不是數(shù)字的字符:^[^0-9]
>>> re.search('[^0-9]', '12345foo')
<_sre.SRE_Match object; span=(5, 6), match='f'>
如果字符出現(xiàn)在字符類中,但不是第一個(gè)字符,則它沒有特殊含義,并且與文本字符匹配:
>>> re.search('[#:^]', 'foo^bar:baz#qux')
<_sre.SRE_Match object; span=(3, 4), match='^'>
間斷性匹配例如座機(jī)號碼有一個(gè) -
>>> 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='-'>
英文的 . 字符匹配除換行符之外的任何單個(gè)字符:.
>>> 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匹配任何字母數(shù)字單詞字符。
單詞字符是大寫和小寫字母、數(shù)字和下劃線 () 字符,
因此本質(zhì)上是:\w 等價(jià)于[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 匹配任何十進(jìn)制數(shù)字字符 等價(jià)于 [0-9]
\D 匹配非數(shù)字 [^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'>
下一篇文章介紹
網(wǎng)絡(luò)圖片
頭條創(chuàng)作挑戰(zhàn)賽#
#醉魚Java#
代碼地址: https://github.com/zuiyu-main/EncryptDemo
在個(gè)別特殊領(lǐng)域中,數(shù)據(jù)的安全問題是非常的重要的,所以需要數(shù)據(jù)庫存儲的數(shù)據(jù)是需要加密存儲的。所以也就引申出來本文這個(gè)問題,加密之后的密文,還能模糊檢索嗎,如果能檢查,如何做模糊檢索呢?
現(xiàn)在的系統(tǒng)設(shè)計(jì)中,常見的加密字段有、密碼、身份證號、手機(jī)號、住址信息、銀行卡、信用卡以及個(gè)別行業(yè)的敏感信息。這些信息對加密的要求也不一樣,對于密碼來說,一般使用不可逆的加密算法就可以,一般不會用到檢索。但是對于身份證號或者個(gè)別領(lǐng)域中的中文信息,我們是需要支持密文模糊匹配的,下面我們就來看看有哪些實(shí)現(xiàn)方式。
本來主要講兩種常規(guī)的簡單加密做法,主要目標(biāo)為能實(shí)現(xiàn)密文的模糊查詢。下面來跟我看第一種。
常規(guī)加密的密文檢索功能根據(jù)4位英文字符(半角),2個(gè)中文字符(全角)作為一個(gè)檢索條件,將一個(gè)字段拆分為多個(gè)字段。
比如:zuiyu123
使用4個(gè)字符為一組的加密方式。
第一組 zuiy,第二組uiyu,第三組iyu1,第四組yu12,第五組u123...如果字符串很長,依次類推下去。
如果需要檢索所有包含檢索條件 uiyu 的數(shù)據(jù),加密字符后通過 key like ‘%加密uiyu的密文%’查詢。
所以這種實(shí)現(xiàn)方式就會有一種問題就是,隨著加密字符串的增加,密文也會變的越大,所以一般用此處方式需要注意數(shù)據(jù)庫中的字段長度限制。
需要注意的是,使用此處方式有一定的限制:
1、支持模糊檢索加密,但是加密的密文隨原文長度增長。
2、支持的模糊檢索條件必須大于等于4個(gè)英文數(shù)字或者2個(gè)漢字,不支持短的查詢(自定義該局限性,業(yè)界常用的就是4個(gè)英文數(shù)字或者2個(gè)漢字,再短的長度不建議支持,因?yàn)榉衷~組合會增多從而導(dǎo)致存儲的成本增加,反而安全性降低。)。
3、返回的列表不是很精確,需要二次篩選,先解密在進(jìn)一步篩選。
字符串拆分的代碼如下:
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);
// 如果到了最后一個(gè)分組,則不再循環(huán)第一個(gè)字符
if (i + chunkSize >=length) {
break;
}
}
log.info("分詞結(jié)果:[{}]",strList);
return strList;
}
對于上述文本zuiyu123分詞效果如下
下面來看下中文的分詞效果:
檢索一下,只要我們使用的是包含上述分詞結(jié)果的條件我們就可以檢索的到。
比如我們檢索個(gè)蛋白質(zhì)
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字段的內(nèi)容長度非常的長,所以我們要注意數(shù)據(jù)庫字段長度限制。
除了上面這個(gè)方式外,發(fā)散一下思維,如果你用過 Elasticsearch 的話,會不會有點(diǎn)想法呢?
因?yàn)樵谥形牡膱鼍爸校形募热灰衷~,選擇專業(yè)的分詞器應(yīng)該是更合理的啊,所以我們可以使用???
對的,你沒猜錯(cuò),既然是要分詞,對于特殊的中文業(yè)務(wù)場景,直接使用 Elasticsearch 的分詞器分詞不就好了嗎,然后再用 Elasticsearch 的強(qiáng)大檢索能力,不就可以滿足我們的模糊檢索需求了嗎,想到就去做,下面就跟著我一起來看下如果用 Elasticsearch 的分詞實(shí)現(xiàn)密文模糊檢索。
使用分詞器分詞進(jìn)行密文檢索的原理:
1、使用 Elasticsearch 自帶的正則分詞器對加密后的密文進(jìn)行分詞。
2、檢索時(shí)使用 Elasticsearch 的match進(jìn)行檢索。
本文演示使用AES進(jìn)行加解密,所以分詞器我就直接使用正則匹配,將密文中的內(nèi)容按照==進(jìn)行拆分。
下面我們一起進(jìn)入代碼時(shí)間,跟隨著我的腳本來看看分詞密文檢索是什么樣的。
也歡迎你來實(shí)操體驗(yàn)一下,有什么問題歡迎評論區(qū)留言告訴我,也可以關(guān)注《醉魚Java》,私信我。
如果使用 7+、8+ 的需要修改為對應(yīng)的版本。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"
}
}
}
}
}
其實(shí)不難發(fā)現(xiàn),我們使用 AES 加密,就是對分詞之后的每個(gè)詞語進(jìn)行加密,然后組成一個(gè)新的字符串。
還是上面那句話魚肉的蛋白質(zhì)含量真的高,我們看一下分詞結(jié)果。
所以我們按照==拆分之后,檢索式再通過加密之后的密文進(jìn)行檢索,也就相當(dāng)于分詞檢索了。
檢索結(jié)果如下:
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}]
密文的模糊查詢就是以空間成本換取的。相比于存儲原文,密文比原文增長了好幾倍。
所以根據(jù)你的業(yè)務(wù)場景,選擇一個(gè)合適的加密算法才是最優(yōu)解。
https://open.taobao.com/docV3.htm?docId=106213&docType=1
https://ningyu1.github.io/20201230/encrypted-data-fuzzy-query.html
正在參加一場關(guān)鍵的技術(shù)面試,對面坐著一位經(jīng)驗(yàn)豐富的面試官。他微笑著提出一個(gè)問題:“能否實(shí)現(xiàn)一個(gè)模糊搜索功能,用JavaScript來寫?”這個(gè)問題看似簡單,但它考驗(yàn)的不僅是你的編程技巧,還考察你在實(shí)際場景中解決問題的能力和思維方式。
為了幫助你在這種場景下表現(xiàn)出色,我將帶你一起實(shí)現(xiàn)一個(gè)簡單但有效的模糊搜索功能,并詳細(xì)解釋其中的關(guān)鍵點(diǎn)。掌握這項(xiàng)技術(shù),不僅能讓你在面試中脫穎而出,還能在實(shí)際工作中為用戶提供更好的搜索體驗(yàn)。
面試官首先解釋了“模糊搜索”的概念。模糊搜索是一種技術(shù),它允許你在文本中找到與用戶輸入接近的結(jié)果,即使輸入中存在小的錯(cuò)誤或字符順序不完全匹配。這在處理用戶可能拼錯(cuò)字或鍵入字符順序不一致時(shí)特別有用。
接下來,面試官給出了一組字符串?dāng)?shù)組,要求你在這個(gè)數(shù)組中實(shí)現(xiàn)模糊搜索。你開始思考,決定使用“滑動(dòng)窗口”技術(shù)來解決這個(gè)問題。你在面試官的注視下開始編寫代碼:
const arr=[
"JavaScript",
"TypeScript",
"Python",
"Java",
"Ruby on Rails",
"ReactJS",
"Angular",
"Vue.js",
"Node.js",
"Django",
"Spring Boot",
"Flask",
"Express.js",
];
面試官點(diǎn)頭示意你繼續(xù)。你明白,要實(shí)現(xiàn)這個(gè)功能,關(guān)鍵在于編寫一個(gè)能逐字符檢查匹配的函數(shù)。于是你寫下了如下代碼:
const fuzzySearch=(str, query)=>
{
str=str.toLowerCase(); // 將字符串轉(zhuǎn)換為小寫,確保不區(qū)分大小寫
query=query.toLowerCase(); // 同樣轉(zhuǎn)換查詢字符串
let i=0, lastSearched=-1, current=query[i];
while (current)
{
// 使用 !~ 來判斷當(dāng)前字符是否在目標(biāo)字符串中按順序出現(xiàn)
if (!~(lastSearched=str.indexOf(current, lastSearched + 1)))
{
return false; // 如果沒找到,則返回 false
};
current=query[++i]; // 查找下一個(gè)字符
}
return true; // 如果所有字符都找到,則返回 true
};
在編寫代碼的過程中,你停下來向面試官解釋道,滑動(dòng)窗口是一種常見的算法技巧,特別適用于字符串和數(shù)組的處理問題。滑動(dòng)窗口的核心思想是在數(shù)據(jù)結(jié)構(gòu)內(nèi)保持一個(gè)“窗口”,逐步滑動(dòng)窗口的位置進(jìn)行檢查或計(jì)算。
在 fuzzySearch 函數(shù)中,滑動(dòng)窗口的概念被用來逐字符地在目標(biāo)字符串中查找查詢字符串中的字符。每次找到一個(gè)字符后,搜索的起始位置會向前移動(dòng),確保后續(xù)字符的匹配不會回到已經(jīng)匹配過的位置,從而保證字符匹配的順序性。
接下來,你向面試官逐步解釋了每一行代碼的邏輯:
面試官顯然對你的解釋感到滿意,你繼續(xù)編寫用于過濾整個(gè)數(shù)組的函數(shù):
const search=function(arr, query)
{
return arr.filter((e)=> fuzzySearch(e, query)); // 使用 fuzzySearch 過濾數(shù)組
};
然后你運(yùn)行了代碼,并向面試官展示了模糊搜索的效果:
console.log(search(arr, 'Java')); // 輸出 [ 'JavaScript', 'Java' ]
面試官看了輸出結(jié)果,點(diǎn)頭稱贊。他認(rèn)可了你如何通過這個(gè)方法在字符串?dāng)?shù)組中實(shí)現(xiàn)了模糊搜索,并展示了實(shí)際效果。
在這個(gè)面試場景中,你不僅展示了扎實(shí)的JavaScript基礎(chǔ),還通過簡潔而高效的代碼,解決了一個(gè)實(shí)際問題。你的表現(xiàn)讓面試官印象深刻,這也證明了你在面對挑戰(zhàn)時(shí)的思維方式和解決問題的能力。
面試不僅是展示你掌握多少知識,更是展示你解決問題的能力和思維方式。愿你在每一場面試中都能從容應(yīng)對,拿下心儀的Offer!
*請認(rèn)真填寫需求信息,我們會在24小時(shí)內(nèi)與您取得聯(lián)系。