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
Python 編程中,不可見零寬度字符可能會在各種場景下悄悄出現,對文本處理造成干擾。這些字符在視覺上并不顯現,但它們的存在可能會導致字符串比較失敗、正則表達式匹配錯誤、編碼問題等多種問題。本文將深入探討這些字符的識別方法、處理策略以及實際應用場景,并附上相應的代碼示例。
識別不可見零寬度字符通常涉及到對字符編碼和 Unicode 標準的了解。Python 提供了多種工具和函數來幫助我們檢測這些字符。
例如,我們可以使用 ord() 函數來檢查字符的 Unicode 碼點,進而判斷它是否為不可見零寬度字符。下面是一個簡單的示例:
def contains_zero_width_chars(s):
for char in s:
# 檢查是否屬于零寬度字符的 Unicode 范圍
if ord(char) in range(8202, 8208): # 舉例:零寬度字符范圍
return True
return False
text="Hello\u200bWorld" # 包含一個零寬度空格
print(contains_zero_width_chars(text)) # 輸出:True
此外,正則表達式也是檢測不可見零寬度字符的強大工具。例如,我們可以使用 re 模塊來查找字符串中的零寬度空格:
import re
text="Hello\u200bWorld" # 包含一個零寬度空格
zero_width_space=re.search(r'\u200b', text)
if zero_width_space:
print("Found zero-width space!")
else:
print("No zero-width space found.")
一旦識別出不可見零寬度字符,我們可以采取多種策略來處理它們,例如移除、替換或忽略這些字符。
移除字符:
import re
def remove_zero_width_chars(s):
# 使用正則表達式替換所有零寬度字符為空字符串
return re.sub(r'[\u2000-\u200F]', '', s)
text="Hello\u200bWorld"
cleaned_text=remove_zero_width_chars(text)
print(cleaned_text) # 輸出:HelloWorld
替換字符:
import re
def replace_zero_width_chars(s, replacement=' '):
# 使用正則表達式替換所有零寬度字符為指定字符
return re.sub(r'[\u2000-\u200F]', replacement, s)
text="Hello\u200bWorld"
replaced_text=replace_zero_width_chars(text)
print(replaced_text) # 輸出:Hello World
不可見零寬度字符在實際應用中可能出現在多種場景,以下是一些例子:
1. 文本處理與清洗:
在文本處理任務中,如自然語言處理、數據挖掘或搜索引擎中,清洗文本數據是非常重要的步驟。不可見零寬度字符可能會導致分詞錯誤、關鍵詞匹配失敗等問題,因此需要在預處理階段進行識別和清理。
2. 網頁內容爬取:
從網頁爬取文本時,由于 HTML 或 CSS 的原因,可能會包含不可見零寬度字符。這些字符可能會影響后續的數據分析或展示,因此需要去除。
3. 用戶輸入驗證:
在接收用戶輸入時,為確保數據的完整性和準確性,需要檢查并處理不可見零寬度字符。這些字符可能是用戶無意中引入的,或者是惡意用戶為了繞過某些驗證機制而故意插入的。
4. 跨平臺文件傳輸:
在跨平臺文件傳輸或文本編輯過程中,由于不同平臺或軟件對字符編碼的處理差異,可能會引入不可見零寬度字符。在文件接收方,需要處理這些字符以確保數據的一致性。
通過了解不可見零寬度字符的識別和處理方法,并結合實際應用場景,我們可以更好地處理文本數據,提高程序的健壯性和準確性。在編寫代碼時,應該始終注意檢查和處理這些潛在的字符問題。
最近發現某個數據采集的系統拿下來的數據,有些字段的JSON被莫名截斷了,導致后續數據分析的時候解析JSON失敗。
類似這樣
{"title": "你好
或者這樣,多了個雙引號啥的
{"title":""你好"}
因為數據庫是Oracle,起初以為是Oracle這老古董出問題了,結果一番折騰,把每條寫入數據的SQL語句都拿出來,看起來里面的JSON格式都沒問題。
這也太詭異了吧,看起來沒毛病,但就為啥JSON被隨機截斷呢?
最后我試著把整段SQL放在Rider的 query console 里面執行,然后再去數據庫里讀取這段JSON,居然發現變成這樣了:
{"title":"?你好"}
啊這,看到這個大大的問號,立刻就能知道這個“你好”里面不止是這兩個字,肯定含有不可見的Unicode字符。
然后把這段JSON復制出來,用16進制模式打開,果然看到在“你好”前面有一個 \u0020
的字符…
這里再附上部分 Unicode 表格
U+ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0000 | NUL | SOH | STX | ETX | EOT | ENQ | ACK | BEL | BS | HT | LF | VT | FF | CR | SO | SI |
0010 | DLE | DC1 | DC2 | DC3 | DC4 | NAK | SYN | ETB | CAN | EM | SUB | ESC | FS | GS | RS | US |
0020 | ! | " | # | $ | % | & | ' | ( | ) | * | + | , | - | . | / | |
0030 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; | < | = | > | ? |
0040 | @ | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O |
0050 | P | Q | R | S | T | U | V | W | X | Y | Z | [ | \ | ] | ^ | _ |
0060 | ` | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o |
可以看到上面那個 \u0020
在第三行第一列,是一個不可見字符,躲在標題的前面
也就是因為這個 Unicode 字符,Oracle無法正確解析,所以導致了插入數據的時候錯亂了
所以破案了,就是系統前臺使用人員,在輸入的時候不知道咋滴搞了個Unicode字符進去…
解決方法就是我這邊采集的時候再做一次過濾…
沒想到C#要搞個過濾 Unicode 還挺折騰的,資料太少…
最后還是參考了Java的資料搞的。==...
代碼如下
寫了個擴展方法來過濾
public static class StringExt {
// 控制字符
private static readonly Regex ControlCharRegex=new Regex(@"[\p{C}]", RegexOptions.Compiled);
/// <summary>
/// 移除控制字符
/// </summary>
public static string RemoveControlChars(this string text) {
return ControlCharRegex.Replace(text, string.Empty);
}
}
要使用的時候就這樣
var outStr="帶有Unicode的字符串".RemoveControlChars();
搞定。
avaScript奇技淫巧:隱形字符
本文,分享一種奇特的JS編程技巧,功能是:可以使字符串“隱形”、不可見!
如下圖所示,一個字符串經物別的操作之后,其長度有621字節,但內容卻是“隱形”不可見的!
這個技術可以應用到很多領域,非常具有實用性。
比如:代碼加密、數據加密、文字隱藏、內容保密、隱形水印,等等。
實現字符串隱形,技術原理是“零寬字符”。
什么是“零寬字符”呢?
在Unicode編碼中,有一類奇怪的字符格式,它們不可見、不可打印,主要用于調整字符的顯示格式。
常見零寬字符類型:
空格符:格式為U+200B,用于較長字符的換行分隔;
非斷空格符:格式為U+FEFF,用于阻止特定位置的換行分隔;
連字符:格式為U+200D,用于阿拉伯文與印度語系等文字中,使不會發生連字的字符間產生連字效果;
斷字符:格式為U+200C,用于阿拉伯文、德文、印度語系等文字中,阻止會發生連字的字符間的連字效果;
左至右符:格式為U+200E,用于在混合文字方向的多種語言文本中,規定排版文字書寫方向為左至右;
右至左符:格式為U+200F : 用于在混合文字方向的多種語言文本中,規定排版文字書寫方向為右至左;
在編程實現隱形字符功能時,先將字符串轉為二進制,再將二進制中的1轉換為\u200b;0轉換為\u200c;空格轉換為\u200d,最后使用\ufeff 零寬度非斷空格符作分隔符。這幾種unicode字符都是不可見的,因此最終轉化完成并組合后,就會形成一個全不可見的“隱形”字符串。
function text_2_binary(text){
return text.split('').map(function(char){ return char.charCodeAt(0).toString(2)}).join(' ');
}
function binary_2_hidden_text(binary){
return binary.split('').map(function (binary_num){
var num=parseInt(binary_num, 10);
if (num===1) {
return '\u200b';
} else if(num===0) {
return '\u200c';
}
return '\u200d';
}).join('\ufeff')
}
var text="jshaman是專業且強大的JS代碼混淆加密工具";
var binary_text=text_2_binary(text);
var hidden_text=binary_2_hidden_text(binary_text);
console.log("原始字符串:",text);
console.log("二進制:",binary_text);
console.log("隱藏字符:",hidden_text,"隱藏字符長度:",hidden_text.length);
接下來介紹“隱形”后的內容如何還原。
在了解上文內容之后,知道了字符隱形的原理,再結合源代碼可知:還原隱形內容,即進行逆操作:將隱形的unicode編碼轉化成二進制,再將二進制轉成原本字符。
直接給出源碼:
function hidden_text_2_binary(string){
return string.split('\ufeff').map(function(char){
if (char==='\u200b') {
return '1';
} else if(char==='\u200c') {
return '0';
}
return ' ';
}).join('')
}
function binary_2_Text(binaryStr){
var text=""
binaryStr.split(' ').map(function(num){
text +=String.fromCharCode(parseInt(num, 2));
}).join('');
return text.toString();
}
console.log("隱形字符轉二進制:",hidden_text_2_binary(hidden_text));
console.log("二進制轉原始字符:",binary_2_Text(hidden_text_2_binary(hidden_text)));
運行效果:
如果在代碼中直接提供“隱形”字符內容,比如ajax通信時,將“隱形”字符由后端傳給前端,并用以上解密方法還原,那么這種方式傳遞的內容會是非常隱秘的。
但還是存在一個安全問題:他人查看JS源碼,能看到解密函數,這可能引起加密方法泄露、被人推導出加密、解密方法。
對此問題,可以采用JS代碼混淆加密,進一步提升整體JS代碼安全性。
用JShaman對上面兩個解密函數進行代碼混淆加密。
如下圖,來到JShaman網站,貼入要加密的JS代碼:
使用如下配置:
得到加密的JS代碼:
將代碼粘貼回源文件中:
加密的JS代碼,運行起來跟之前完全一樣。
但此時,已不再是裸露的透明JS代碼,從這混亂復雜的代碼中很難看出功能邏輯。
注:“隱形字符”技術,可用于前后端JS執行環境,即可在Node.JS中執行,也可在瀏覽器中使用。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。