整合營(yíng)銷(xiāo)服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          Python 中的不可見(jiàn)零寬度字符

          Python 中的不可見(jiàn)零寬度字符

          Python 編程中,不可見(jiàn)零寬度字符可能會(huì)在各種場(chǎng)景下悄悄出現(xiàn),對(duì)文本處理造成干擾。這些字符在視覺(jué)上并不顯現(xiàn),但它們的存在可能會(huì)導(dǎo)致字符串比較失敗、正則表達(dá)式匹配錯(cuò)誤、編碼問(wèn)題等多種問(wèn)題。本文將深入探討這些字符的識(shí)別方法、處理策略以及實(shí)際應(yīng)用場(chǎng)景,并附上相應(yīng)的代碼示例。

          識(shí)別不可見(jiàn)零寬度字符

          識(shí)別不可見(jiàn)零寬度字符通常涉及到對(duì)字符編碼和 Unicode 標(biāo)準(zhǔn)的了解。Python 提供了多種工具和函數(shù)來(lái)幫助我們檢測(cè)這些字符。

          例如,我們可以使用 ord() 函數(shù)來(lái)檢查字符的 Unicode 碼點(diǎn),進(jìn)而判斷它是否為不可見(jiàn)零寬度字符。下面是一個(gè)簡(jiǎn)單的示例:

          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"  # 包含一個(gè)零寬度空格
          print(contains_zero_width_chars(text))  # 輸出:True

          此外,正則表達(dá)式也是檢測(cè)不可見(jiàn)零寬度字符的強(qiáng)大工具。例如,我們可以使用 re 模塊來(lái)查找字符串中的零寬度空格:

          import re
          
          text="Hello\u200bWorld"  # 包含一個(gè)零寬度空格  
          zero_width_space=re.search(r'\u200b', text)
          
          if zero_width_space:
              print("Found zero-width space!")
          else:
              print("No zero-width space found.")

          處理不可見(jiàn)零寬度字符

          一旦識(shí)別出不可見(jiàn)零寬度字符,我們可以采取多種策略來(lái)處理它們,例如移除、替換或忽略這些字符。

          移除字符

          import re
          
          
          def remove_zero_width_chars(s):
              # 使用正則表達(dá)式替換所有零寬度字符為空字符串  
              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=' '):
              # 使用正則表達(dá)式替換所有零寬度字符為指定字符  
              return re.sub(r'[\u2000-\u200F]', replacement, s)
          
          
          text="Hello\u200bWorld"
          replaced_text=replace_zero_width_chars(text)
          print(replaced_text)  # 輸出:Hello World

          應(yīng)用場(chǎng)景

          不可見(jiàn)零寬度字符在實(shí)際應(yīng)用中可能出現(xiàn)在多種場(chǎng)景,以下是一些例子:

          1. 文本處理與清洗
          在文本處理任務(wù)中,如自然語(yǔ)言處理、數(shù)據(jù)挖掘或搜索引擎中,清洗文本數(shù)據(jù)是非常重要的步驟。不可見(jiàn)零寬度字符可能會(huì)導(dǎo)致分詞錯(cuò)誤、關(guān)鍵詞匹配失敗等問(wèn)題,因此需要在預(yù)處理階段進(jìn)行識(shí)別和清理。

          2. 網(wǎng)頁(yè)內(nèi)容爬取
          從網(wǎng)頁(yè)爬取文本時(shí),由于 HTML 或 CSS 的原因,可能會(huì)包含不可見(jiàn)零寬度字符。這些字符可能會(huì)影響后續(xù)的數(shù)據(jù)分析或展示,因此需要去除。

          3. 用戶輸入驗(yàn)證
          在接收用戶輸入時(shí),為確保數(shù)據(jù)的完整性和準(zhǔn)確性,需要檢查并處理不可見(jiàn)零寬度字符。這些字符可能是用戶無(wú)意中引入的,或者是惡意用戶為了繞過(guò)某些驗(yàn)證機(jī)制而故意插入的。

          4. 跨平臺(tái)文件傳輸
          在跨平臺(tái)文件傳輸或文本編輯過(guò)程中,由于不同平臺(tái)或軟件對(duì)字符編碼的處理差異,可能會(huì)引入不可見(jiàn)零寬度字符。在文件接收方,需要處理這些字符以確保數(shù)據(jù)的一致性。

          通過(guò)了解不可見(jiàn)零寬度字符的識(shí)別和處理方法,并結(jié)合實(shí)際應(yīng)用場(chǎng)景,我們可以更好地處理文本數(shù)據(jù),提高程序的健壯性和準(zhǔn)確性。在編寫(xiě)代碼時(shí),應(yīng)該始終注意檢查和處理這些潛在的字符問(wèn)題。

          背景

          最近發(fā)現(xiàn)某個(gè)數(shù)據(jù)采集的系統(tǒng)拿下來(lái)的數(shù)據(jù),有些字段的JSON被莫名截?cái)嗔耍瑢?dǎo)致后續(xù)數(shù)據(jù)分析的時(shí)候解析JSON失敗。

          類(lèi)似這樣

          {"title": "你好

          或者這樣,多了個(gè)雙引號(hào)啥的

          {"title":""你好"}

          因?yàn)閿?shù)據(jù)庫(kù)是Oracle,起初以為是Oracle這老古董出問(wèn)題了,結(jié)果一番折騰,把每條寫(xiě)入數(shù)據(jù)的SQL語(yǔ)句都拿出來(lái),看起來(lái)里面的JSON格式都沒(méi)問(wèn)題。

          這也太詭異了吧,看起來(lái)沒(méi)毛病,但就為啥JSON被隨機(jī)截?cái)嗄兀?/p>

          最后我試著把整段SQL放在Rider的 query console 里面執(zhí)行,然后再去數(shù)據(jù)庫(kù)里讀取這段JSON,居然發(fā)現(xiàn)變成這樣了:

          {"title":"?你好"}

          啊這,看到這個(gè)大大的問(wèn)號(hào),立刻就能知道這個(gè)“你好”里面不止是這兩個(gè)字,肯定含有不可見(jiàn)的Unicode字符。

          然后把這段JSON復(fù)制出來(lái),用16進(jìn)制模式打開(kāi),果然看到在“你好”前面有一個(gè) \u0020 的字符…

          2Unicode碼表

          • 0000-007F:C0控制符及基本拉丁文 (C0 Control and Basic Latin)
          • 0080-00FF:C1控制符及拉丁文補(bǔ)充-1 (C1 Control and Latin 1 Supplement)
          • 0100-017F:拉丁文擴(kuò)展-A (Latin Extended-A)
          • 0180-024F:拉丁文擴(kuò)展-B (Latin Extended-B)
          • 0250-02AF:國(guó)際音標(biāo)擴(kuò)展 (IPA Extensions)
          • 02B0-02FF:空白修飾字母 (Spacing Modifiers)
          • ……

          這里再附上部分 Unicode 表格

          U+0123456789ABCDEF
          0000NULSOHSTXETXEOTENQACKBELBSHTLFVTFFCRSOSI
          0010DLEDC1DC2DC3DC4NAKSYNETBCANEMSUBESCFSGSRSUS
          0020
          !"#$%&'()*+,-./
          00300123456789:;<=>?
          0040@ABCDEFGHIJKLMNO
          0050PQRSTUVWXYZ[\]^_
          0060`abcdefghijklmno

          可以看到上面那個(gè) \u0020 在第三行第一列,是一個(gè)不可見(jiàn)字符,躲在標(biāo)題的前面

          也就是因?yàn)檫@個(gè) Unicode 字符,Oracle無(wú)法正確解析,所以導(dǎo)致了插入數(shù)據(jù)的時(shí)候錯(cuò)亂了

          所以破案了,就是系統(tǒng)前臺(tái)使用人員,在輸入的時(shí)候不知道咋滴搞了個(gè)Unicode字符進(jìn)去…

          解決方法就是我這邊采集的時(shí)候再做一次過(guò)濾…

          沒(méi)想到C#要搞個(gè)過(guò)濾 Unicode 還挺折騰的,資料太少…

          最后還是參考了Java的資料搞的。==...

          3代碼

          代碼如下

          寫(xiě)了個(gè)擴(kuò)展方法來(lái)過(guò)濾

          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);
          }
          }

          要使用的時(shí)候就這樣

          var outStr="帶有Unicode的字符串".RemoveControlChars();

          搞定。

          4參考資料

          • UniCode編碼表及部分不可見(jiàn)字符過(guò)濾方案 - https://www.cnblogs.com/fan-yuan/p/8176886.html
          • https://stackoverflow.com/questions/6198986/how-can-i-replace-non-printable-unicode-characters-in-java

          avaScript奇技淫巧:隱形字符

          本文,分享一種奇特的JS編程技巧,功能是:可以使字符串“隱形”、不可見(jiàn)!

          效果展示

          如下圖所示,一個(gè)字符串經(jīng)物別的操作之后,其長(zhǎng)度有621字節(jié),但內(nèi)容卻是“隱形”不可見(jiàn)的!

          功能用途

          這個(gè)技術(shù)可以應(yīng)用到很多領(lǐng)域,非常具有實(shí)用性。

          比如:代碼加密、數(shù)據(jù)加密、文字隱藏、內(nèi)容保密、隱形水印,等等。

          原理介紹

          實(shí)現(xiàn)字符串隱形,技術(shù)原理是“零寬字符”。

          什么是“零寬字符”呢?

          在Unicode編碼中,有一類(lèi)奇怪的字符格式,它們不可見(jiàn)、不可打印,主要用于調(diào)整字符的顯示格式。

          常見(jiàn)零寬字符類(lèi)型:

          空格符:格式為U+200B,用于較長(zhǎng)字符的換行分隔;

          非斷空格符:格式為U+FEFF,用于阻止特定位置的換行分隔;

          連字符:格式為U+200D,用于阿拉伯文與印度語(yǔ)系等文字中,使不會(huì)發(fā)生連字的字符間產(chǎn)生連字效果;

          斷字符:格式為U+200C,用于阿拉伯文、德文、印度語(yǔ)系等文字中,阻止會(huì)發(fā)生連字的字符間的連字效果;

          左至右符:格式為U+200E,用于在混合文字方向的多種語(yǔ)言文本中,規(guī)定排版文字書(shū)寫(xiě)方向?yàn)樽笾劣遥?/p>

          右至左符:格式為U+200F : 用于在混合文字方向的多種語(yǔ)言文本中,規(guī)定排版文字書(shū)寫(xiě)方向?yàn)橛抑磷螅?/p>

          在編程實(shí)現(xiàn)隱形字符功能時(shí),先將字符串轉(zhuǎn)為二進(jìn)制,再將二進(jìn)制中的1轉(zhuǎn)換為\u200b;0轉(zhuǎn)換為\u200c;空格轉(zhuǎn)換為\u200d,最后使用\ufeff 零寬度非斷空格符作分隔符。這幾種unicode字符都是不可見(jiàn)的,因此最終轉(zhuǎn)化完成并組合后,就會(huì)形成一個(gè)全不可見(jiàn)的“隱形”字符串。

          功能源碼

          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是專業(yè)且強(qiáng)大的JS代碼混淆加密工具";
          var binary_text=text_2_binary(text);
          var hidden_text=binary_2_hidden_text(binary_text);
          console.log("原始字符串:",text);
          console.log("二進(jìn)制:",binary_text);
          console.log("隱藏字符:",hidden_text,"隱藏字符長(zhǎng)度:",hidden_text.length);

          隱型還原

          接下來(lái)介紹“隱形”后的內(nèi)容如何還原。

          在了解上文內(nèi)容之后,知道了字符隱形的原理,再結(jié)合源代碼可知:還原隱形內(nèi)容,即進(jìn)行逆操作:將隱形的unicode編碼轉(zhuǎn)化成二進(jìn)制,再將二進(jìn)制轉(zhuǎn)成原本字符。

          直接給出源碼:

          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("隱形字符轉(zhuǎn)二進(jìn)制:",hidden_text_2_binary(hidden_text));
          console.log("二進(jìn)制轉(zhuǎn)原始字符:",binary_2_Text(hidden_text_2_binary(hidden_text)));

          運(yùn)行效果:

          如果在代碼中直接提供“隱形”字符內(nèi)容,比如ajax通信時(shí),將“隱形”字符由后端傳給前端,并用以上解密方法還原,那么這種方式傳遞的內(nèi)容會(huì)是非常隱秘的。

          但還是存在一個(gè)安全問(wèn)題:他人查看JS源碼,能看到解密函數(shù),這可能引起加密方法泄露、被人推導(dǎo)出加密、解密方法。

          對(duì)此問(wèn)題,可以采用JS代碼混淆加密,進(jìn)一步提升整體JS代碼安全性。

          JS代碼加密

          JShaman對(duì)上面兩個(gè)解密函數(shù)進(jìn)行代碼混淆加密。

          如下圖,來(lái)到JShaman網(wǎng)站,貼入要加密的JS代碼:

          使用如下配置:

          得到加密的JS代碼:

          將代碼粘貼回源文件中:

          加密的JS代碼,運(yùn)行起來(lái)跟之前完全一樣。

          但此時(shí),已不再是裸露的透明JS代碼,從這混亂復(fù)雜的代碼中很難看出功能邏輯。

          注:“隱形字符”技術(shù),可用于前后端JS執(zhí)行環(huán)境,即可在Node.JS中執(zhí)行,也可在瀏覽器中使用。


          主站蜘蛛池模板: 国产伦精品一区二区三区在线观看| 国产一区二区三区91| 亚洲AV无码一区二区乱子仑| 狠狠色婷婷久久一区二区三区| 日韩精品无码久久一区二区三| 亚洲国产欧美国产综合一区| 国模无码一区二区三区 | 国产免费一区二区三区| 亚洲一区中文字幕| 亚洲AV无码一区二区三区鸳鸯影院| 久久青青草原一区二区| 国产成人久久精品麻豆一区| 久久99热狠狠色精品一区| 精品一区二区三区在线播放视频| 国产精品99精品一区二区三区| 在线观看日韩一区| 精品无码国产一区二区三区AV| 日本在线电影一区二区三区| AV天堂午夜精品一区| 国偷自产视频一区二区久| 无码国产精品一区二区免费16| 人妻少妇AV无码一区二区| 亚洲日韩激情无码一区| 精品国产区一区二区三区在线观看 | 精品一区二区三区中文| 亚洲AV无码一区二区三区电影| 少妇精品久久久一区二区三区 | 国产精品一区二区久久精品无码| 中文字幕乱码一区久久麻豆樱花| 久久高清一区二区三区| 精品国产一区二区三区免费| 国产亚洲3p无码一区二区| 国产一区二区电影| 亚洲国产精品一区二区久| 人妻精品无码一区二区三区| 一区二区三区内射美女毛片| 精品人妻少妇一区二区三区不卡| 一区二区无码免费视频网站| 无码一区二区三区视频| 国产一区三区二区中文在线| 久久免费视频一区|