基於Python實現花里胡哨文字生成器 h1>
在瀏覽網頁的過程中,時常會看到各種“不同尋常”的文字,形如:
![](http://daogezhiyuan-article.oss-cn-beijing.aliyuncs.com/win3000/pic/e7359090-75b3-43a7-b6cb-741a0533c4ac.jpg)
![](http://daogezhiyuan-article.oss-cn-beijing.aliyuncs.com/win3000/pic/5f1e6136-ebae-4932-bef2-76c2d51c8e77.jpg)
這些文字總會在普通文字的基礎上,附帶許多奇特的符號。其基本原理是Unicode的結合附加符號與普通文字的疊加,想要製作一個這樣的文字生成器,首先就需要了解這樣的文字是怎麼使用Unicode編碼得到的
基本理論
Unicode的作用
最開始的時候,人們使用長度僅1字節的ASCII碼來表示128種字符,其中每個字符都對應一個編碼,例如:二進制編碼01000001 2 _2 2表示字符'A',則在程序中,字符'A'就是用01000001這樣的二進制序列來保存的
後來,隨著需求的增加,只能表示128種字符的ASCII碼逐漸地“不夠用”了:ASCII碼顯然是沒有包含中文、日文、韓文這些文字的,如果要對這些字進行編碼,就需要單獨制定一種新的編碼規則,於是Unicode由此誕生
Unicode使用了更多的字節,將全球各地的語言文字都包含了進去。這樣一來,在Unicode的規則之下,任何國家的文字就都可以有一個對應的編碼了。也就是說,使用Unicode後,就可以在程序中使用各國語言(而非一定要是ASCII碼規定的128種字符之一)了
Unicode結合附加符號
Unicode編碼中,有一個分類叫做“結合附加符號”,這便是這些奇形怪狀的文字的“萬惡之源”:將普通的文字與這些結合附加符號相結合,就會發生一些可能之前從來沒有見過的奇觀
打開python的idle界面,輸入:
sss = "\u0041\u030A"print(sss)
可以觀察到這樣的現象:
![](http://daogezhiyuan-article.oss-cn-beijing.aliyuncs.com/win3000/pic/e2e73368-bfaa-4d77-b69b-fc59b707fc09.jpg)
注意到不僅是輸出了一個A,而且還在A的上面多了一個圓! \u0041是A的Unicode編碼,而\u030A則是一個結合附加符號" ∘ \circ ∘",當這兩個符號結合起來的時候,圓圈就不會單獨占一個位置,而是與A相互結合了起來!
如果將這個\u030A複製多次,則可以不斷地在A的上方生成越來越多的圓,從而起到“穿屏”的效果:
![](http://daogezhiyuan-article.oss-cn-beijing.aliyuncs.com/win3000/pic/933a1a87-f5a2-4f2a-a7f9-f83500d1b74d.jpg)
上述界面是在瀏覽器的開發者工具中的Console運行的結果,而在Python的idle中,顯示的文字是有高度限制的,所以基本上就只保留了第一層的圈,導致視覺效果並不好。實際上,在qq和微信的聊天界面中,也限制了文字的高度,所以復制進去最多就只能看到四五層,在視覺上並不夠震撼
除了圓圈之外,還有其他的很多結合附加符號,他們都可以與前面那個文字相疊加。結合附加符號的Unicode編碼位於第0平面(具體概念沒了解,但用\u開頭表示就是了)的0300-036F之間,共有112種字符,在https://unicode-table.com/cn/ blocks/combining-diacritical-marks/這個網址上可以搜索這些Unicode碼所對應的符號具體都是些啥,對後續的花里胡哨的選擇很有幫助
程序設計思路
在簡單地提及了關於Unicode的內容後,現在就可以設計一個這樣的文字的生成器了
整理一下目前已知的信息:
1、普通文字+Unicode結合附加符號=在普通文字上追加符號
2、Unicode結合附加符號的編碼位於第0平面的0300-036F之間,即編碼在\u0300-\u036F之間
因此,如果想要在文字周圍加上一堆奇怪的符號的話,只要在每個字後面都加上這些Unicode結合符號就行了。 Unicode符號加的越多,看起來就越亂(經實測發現,有些符號會往上疊加,而有些符號則是往下疊加):
![](http://daogezhiyuan-article.oss-cn-beijing.aliyuncs.com/win3000/pic/2c8662f9-0615-421c-b441-0b22d0ef1988.jpg)
這樣,在程序中的思路就很清晰了:先讓用戶輸入一個字符串,然後依次遍歷此字符串中的每個字符,在每個字符後面都加入一定數量的Unicode結合符號。最後,再對新的字符串進行輸出就可以了。偽代碼表示如下:
process convertStr(string) newString <- "" // 初始化一個空串 for i <- 1 to length(string) randomUnicode <- 隨機生成指定數量的Unicode結合符號對應編碼 newString < ;- newString + string[i] + randomUnicode end for return newString
關於Unicode的隨機生成,由於對這112個結合符號不是很了解,所以在這裡就直接在\u0300-\u036F之間隨機選取了。此外,應該還可以讓用戶指定這些結合符號的密度(放在同一個文字上的結合符號數),不然搞太少了沒效果,太多了可能又會爆屏(前幾年在QQ群有看到過疑似是用了大量Unicode結合符號的消息,結果90%的人看到那條消息後,QQ都閃退了……)
有了思路之後,接下來就是實現了
程序實現
分析
用戶的操作是在圖形界面進行的,因此,首先需要一個邊界類:用戶接口類。而關於字符串的處理,可以單獨使用一個控制類來實現,因此,可以再添加一個控制類:字符串處理類。對應的類圖如下所示:
![](http://daogezhiyuan-article.oss-cn-beijing.aliyuncs.com/win3000/pic/1b9b8457-94ca-4f9b-b0e4-13bf552e00c6.jpg)
設計
這兩個類之間的主要交互只有一個:用戶接口類向字符串處理類發送一個字符串,讓字符串處理類對字符串進行加工,隨後接收加工後的字符串
由此,給字符串處理類分配方法:convertString(str, density)——字符串加工,給用戶接口類分配方法:convert(str, density)——將字符串發送給字符串處理類,讓後者對字符串進行加工並返回加工後的字符串
此外,字符串是從用戶接口類輸入的,因為長度通常都很小,不需要單獨作為一個實體類而存在,所以可以直接作為用戶接口類的一個成員。綜上所述,構造的類圖如下:
![](http://daogezhiyuan-article.oss-cn-beijing.aliyuncs.com/win3000/pic/7e7c2073-47f1-4600-a3a3-bcb7d37cf16e.jpg)
實現
控制類ProString
首先構造控制類ProString,其方法也只有一個,就是上述偽代碼中,過程convertStr(string, density)的實現。新建文件ProString.py:
import randomclass ProString: '''Process string receive from user's interface class''' @staticmethod def convertString(string, density): newString = "" lengthOfStr = len(string) for i in range(lengthOfStr) : randomUnicode = "" for j in range(density): randomUnicode += ("\\u03" + str(int(random.random() * 7)) + str([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'A', 'B', 'C', 'D', 'E', 'F'][int(random.random() * 16)])) # 區分出字母、數字if('a' <= string[i] <= 'z' or 'A' <= string[i] <= 'Z' or '0' <= string[i] <= '9'): part = string[i] else: part = str(string[i].encode("unicode_escape"))[-7:-1] newString += (part + randomUnicode) return newString< /code>
因為各種坑爹的問題,字母和數字需要單獨被區分開來,而漢字則需要先轉換為unicode碼的字符形式,所以才有了非常費解的那段if-else語句
而randomUnicode的生成比較地笨,但最直接的能想到的就是這個方式了……
隨意編寫一個test.py來調用這個過程:
from ProString import *a = ProString.convertString("aaa是", 10)print(a)
得到結果:
a\u0363\u032D\u036B\u0314\u032F\u030E\u0359\u0317\u0337\u030Da\u0328\u0322\u0319\u0309\u035E\u0356\u0356\u0321\u033D\u0349a\u033B\ u0331\u036A\u0306\u030A\u0306\u0317\u0325\u032E\u0306\u662f\u032F\u036E\u0323\u034B\u0349\u0351\u032D\u0369\u0322\u0323
這正是想要的返回結果,將其複製到瀏覽器開發者工具的Console上查看效果:
![](http://daogezhiyuan-article.oss-cn-beijing.aliyuncs.com/win3000/pic/5a4dcddc-0dd3-4618-b241-205143806193.jpg)
漢字沒有顯示出來,但是不要緊,在其他地方還是可以正常顯示的
接下來再到用戶接口類:
用戶接口類Main
此處使用qt對圖形界面進行設計,首先是一個歸納出的模板:
import sysfrom PySide2.QtUiTools import QUiLoaderfrom PySide2.QtWidgets import QApplicationfrom PySide2.QtCore import QFile, QIODeviceif __name__ == "__main__": app = QApplication(sys.argv) ui_file_name = "form.ui" ui_file = QFile (ui_file_name) if not ui_file.open(QIODevice.ReadOnly): print("Cannot open {}: {}".format(ui_file_name, ui_file.errorString())) sys.exit(-1) loader = QUiLoader() window = loader.load(ui_file) ui_file.close() if not window: print(loader.errorString()) sys.exit(-1) window.show() sys.exit(app.exec_())
使用這段代碼,就可以在運行Main.py的時候,讓python加載一個名為form.ui的圖形化界面文件,並將其打開
現在,先設計圖形界面form.ui。這個過程是在qt creator中完成的:
![](http://daogezhiyuan-article.oss-cn-beijing.aliyuncs.com/win3000/pic/2240c80f-4d33-4f57-a00c-bc8f32624a7b.jpg)
qt creator能夠提供一個良好的可視化界面設計環境,並且還是有開源(免費)版的,非常值得一試
設計出的窗口界面如下:
![](http://daogezhiyuan-article.oss-cn-beijing.aliyuncs.com/win3000/pic/3933113a-fd76-4646-adcc-1752dfacb8d5.jpg)
隨後,在Main.py中,添加調用ProString.convertString的方法:
def convert(): inputString = window.textEdit.toPlainText() # 排除空串if(inputString == ""): return # 排除非法輸入的符號密度density = window.lineEdit.text() try: density = int(density) except: window.plainTextEdit.setPlainText("符號密度應該是數字!") return # 正常執行outputString = ProString.convertString(inputString, density) outputString = outputString.encode("utf-8" ).decode("unicode_escape") window.plainTextEdit.setPlainText(outputString)
並將此方法關聯到按鈕上:
window.pushButton.clicked.connect(convert)
到此,生成器的製作就完成了,下面是運行效果:
效果展示
![](http://daogezhiyuan-article.oss-cn-beijing.aliyuncs.com/win3000/pic/e5ba0218-82a7-423d-b5d6-16c233d18d48.jpg)
![](http://daogezhiyuan-article.oss-cn-beijing.aliyuncs.com/win3000/pic/d7d0a1cc-58ea-4ead-8183-827557495cef.jpg)
放在QQ中嘗試:
![](http://daogezhiyuan-article.oss-cn-beijing.aliyuncs.com/win3000/pic/04056780-1d94-4482-b9a3-134a71a51c9d.jpg)
ohhhhhhhhhhhhhhhhhh
經實測發現,如果要保證可讀性,符號密度設置為8就差不多了,再多一些就會影響文字的閱讀了……
最後,在弄完後才發現,在QQ裡面只要多換幾行,就可以讓下面幾行的符號頂到最頂上,可以用這個方式來彌補高度限制……
源碼
form.ui
<?xml version="1.0" encoding="UTF-8"?><ui version="4.0"> <class>widget</class> <widget class="QWidget" name="widget"> < ;property name="geometry"> <rect> <x>0</x> <y>0</y> <width>1000</width> <height>750</height> < ;/rect> </property> <property name="minimumSize"> <size> <width>1000</width> <height>750</height> </size> </property> ; <property name="maximumSize"> <size> <width>1000</width> <height>750</height> </size> </property> <property name="windowTitle "> <string>Form</string> </property> <widget class="QPushButton" name="pushButton"> <property name="geometry"> <rect> <x> 840</x> <y>10</y> <width>151</width> <height>61</height> </rect> </property> <property name="font" > <font> <family>楷體</family> <pointsize>20</pointsize> </font> </property> <property name="text"> <string>生成</string> </property> </widget> <widget class="QLineEdit" name="lineEdit"> <property name="geometry"> <rect> <x>720< /x> <y>10</y> <width>61</width> <height>61</height> </rect> </property> <property name="font"> <font> <pointsize>20</pointsize> </font> </property> <property name="text"> <string>10</string> </property> <property name="maxLength"> <number>2</number> </property> </widget> <widget class="QLabel" name="label"> <property name="geometry"> ; <rect> <x>540</x> <y>10</y> <width>181</width> <height>61</height> </rect> </property> ; <property name="font"> <font> <family>楷體</family> <pointsize>20</pointsize> </font> </property> <property name=" text"> <string>符號密度</string> </property> </widget> <widget class="QLabel" name="label_2"> <property name="geometry"> <rect> <x>10</x> <y>10</y> <width>211</width> <height>61</height> </rect> </property> <property name="font"> <font> <family>楷體</family> <pointsize>20</pointsize> </font> </property> <property name="text "> <string>待轉換文本</string> </property> </widget> <widget class="QTextEdit" name="textEdit"> <property name="geometry"> <rect> <x>220</x> <y>10</y> <width>311</width> <height>61</height> </rect> </property> <property name="font"> <font> <pointsize>12</pointsize> </font> </property> </widget> <widget class="QPlainTextEdit" name="plainTextEdit "> <property name="geometry"> <rect> <x>10</x> <y>80</y> <width>981</width> <height>661< /height> </rect> </property> <property name="font"> <font> <pointsize>20</pointsize> </font> </property> </widget> ; </widget> <resources/> <connections/></ui>
Main.py h1>import sysfrom PySide2.QtUiTools import QUiLoaderfrom PySide2.QtWidgets import QApplicationfrom PySide2.QtCore import QFile, QIODevicefrom ProString import *def convert(): inputString = window.textEdit.toPlainText() # 排除空串if( inputString == ""): return # 排除非法輸入的符號密度density = window.lineEdit.text() try: density = int(density) except: window.plainTextEdit.setPlainText("符號密度應該是數字! ") return # 正常執行outputString = ProString.convertString(inputString, density) outputString = outputString.encode("utf-8").decode("unicode_escape") window.plainTextEdit.setPlainText(outputString)if __name__ == "__main__" : app = QApplication(sys.argv) ui_file_name = "form.ui" ui_file = QFile(ui_file_name) if not ui_file.open(QIODevice.ReadOnly): print("Cannot open {}: {}".format(ui_file_name, ui_file .errorString())) sys.exit(-1) loader = QUiLoader() window = loader.load(ui_file) ui_file.close() if not window: print(loader.errorString()) sys.exit(-1) window.pushButton.clicked.connect( convert) window.show() sys.exit(app.exec_())
ProString.py
< code>import randomclass ProString: '''Process string receive from user's interface class''' @staticmethod def convertString(string, density): newString = "" lengthOfStr = len(string) for i in range(lengthOfStr): randomUnicode = " " for j in range(density): randomUnicode += ("\\u03" + str(int(random.random() * 7)) + str([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'A', 'B', 'C', 'D', 'E', 'F'][int(random.random() * 16)])) # 區分出字母、數字if('a' <= string[i] <= 'z' or 'A' <= string[i] <= 'Z' or '0' <= string[i] <= ' 9'): part = string[i] else: part = str(string[i].私信小編01即可獲取大量Python學習資料
import sysfrom PySide2.QtUiTools import QUiLoaderfrom PySide2.QtWidgets import QApplicationfrom PySide2.QtCore import QFile, QIODevicefrom ProString import *def convert(): inputString = window.textEdit.toPlainText() # 排除空串if( inputString == ""): return # 排除非法輸入的符號密度density = window.lineEdit.text() try: density = int(density) except: window.plainTextEdit.setPlainText("符號密度應該是數字! ") return # 正常執行outputString = ProString.convertString(inputString, density) outputString = outputString.encode("utf-8").decode("unicode_escape") window.plainTextEdit.setPlainText(outputString)if __name__ == "__main__" : app = QApplication(sys.argv) ui_file_name = "form.ui" ui_file = QFile(ui_file_name) if not ui_file.open(QIODevice.ReadOnly): print("Cannot open {}: {}".format(ui_file_name, ui_file .errorString())) sys.exit(-1) loader = QUiLoader() window = loader.load(ui_file) ui_file.close() if not window: print(loader.errorString()) sys.exit(-1) window.pushButton.clicked.connect( convert) window.show() sys.exit(app.exec_())
私信小編01即可獲取大量Python學習資料
文章為用戶上傳,僅供非商業瀏覽。發布者:Lomu,轉轉請註明出處: https://www.daogebangong.com/zh-Hant/articles/detail/fancy%20text%20generator.html
评论列表(196条)
测试