花里胡哨文字生成器

内容分享3小时前发布
0 0 0

基于Python实现花里胡哨文字生成器

  在浏览网页的过程中,时常会看到各种“不同寻常”的文字,形如:

花里胡哨文字生成器

花里胡哨文字生成器

  这些文字总会在普通文字的基础上,附带许多奇特的符号。其基本原理是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 = "u0041u030A"
print(sss)

  可以观察到这样的现象:

花里胡哨文字生成器

  注意到不仅是输出了一个A,而且还在A的上面多了一个圆!u0041是A的Unicode编码,而u030A则是一个结合附加符号” ∘ circ ∘”,当这两个符号结合起来的时候,圆圈就不会单独占一个位置,而是与A相互结合了起来!

  如果将这个u030A复制多次,则可以不断地在A的上方生成越来越多的圆,从而起到“穿屏”的效果:

花里胡哨文字生成器

  上述界面是在浏览器的开发者工具中的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符号加的越多,看起来就越乱(经实测发现,有些符号会往上叠加,而有些符号则是往下叠加):

花里胡哨文字生成器

  这样,在程序中的思路就很清晰了:先让用户输入一个字符串,然后依次遍历此字符串中的每个字符,在每个字符后面都加入必定数量的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都闪退了……)

  有了思路之后,接下来就是实现了

程序实现

分析

  用户的操作是在图形界面进行的,因此,第一需要一个边界类:用户接口类。而关于字符串的处理,可以单独使用一个控制类来实现,因此,可以再添加一个控制类:字符串处理类。对应的类图如下所示:

花里胡哨文字生成器

设计

  这两个类之间的主要交互只有一个:用户接口类向字符串处理类发送一个字符串,让字符串处理类对字符串进行加工,随后接收加工后的字符串

  由此,给字符串处理类分配方法:convertString(str, density)——字符串加工,给用户接口类分配方法:convert(str, density)——将字符串发送给字符串处理类,让后者对字符串进行加工并返回加工后的字符串

  此外,字符串是从用户接口类输入的,由于长度一般都很小,不需要单独作为一个实体类而存在,所以可以直接作为用户接口类的一个成员。综上所述,构造的类图如下:

花里胡哨文字生成器

实现

控制类ProString

  第一构造控制类ProString,其方法也只有一个,就是上述伪代码中,过程convertStr(string, density)的实现。新建文件ProString.py:

import random

class 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

  由于各种坑爹的问题,字母和数字需要单独被区分开来,而汉字则需要先转换为unicode码的字符形式,所以才有了超级费解的那段if-else语句

  而randomUnicode的生成比较地笨,但最直接的能想到的就是这个方式了……

  随意编写一个test.py来调用这个过程:

from ProString import *

a = ProString.convertString("aaa是", 10)
print(a)

  得到结果:

au0363u032Du036Bu0314u032Fu030Eu0359u0317u0337u030Dau0328u0322u0319u0309u035Eu0356u0356u0321u033Du0349au033Bu0331u036Au0306u030Au0306u0317u0325u032Eu0306u662fu032Fu036Eu0323u034Bu0349u0351u032Du0369u0322u0323

  这正是想要的返回结果,将其复制到浏览器开发者工具的Console上查看效果:

花里胡哨文字生成器

  汉字没有显示出来,但是不要紧,在其他地方还是可以正常显示的

  接下来再到用户接口类:

用户接口类Main

  此处使用qt对图形界面进行设计,第一是一个归纳出的模板:

import sys
from PySide2.QtUiTools import QUiLoader
from PySide2.QtWidgets import QApplication
from PySide2.QtCore import QFile, QIODevice

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.show()

    sys.exit(app.exec_())

  使用这段代码,就可以在运行Main.py的时候,让python加载一个名为form.ui的图形化界面文件,并将其打开

  目前,先设计图形界面form.ui。这个过程是在qt creator中完成的:

花里胡哨文字生成器

  qt creator能够提供一个良好的可视化界面设计环境,并且还是有开源(免费)版的,超级值得一试

  设计出的窗口界面如下:

花里胡哨文字生成器

  随后,在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)

  到此,生成器的制作就完成了,下面是运行效果:

效果展示

花里胡哨文字生成器

花里胡哨文字生成器

  放在QQ中尝试:

花里胡哨文字生成器

  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

import sys
from PySide2.QtUiTools import QUiLoader
from PySide2.QtWidgets import QApplication
from PySide2.QtCore import QFile, QIODevice
from 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

import random

class 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

私信小编01即可获取大量Python学习资料

© 版权声明

相关文章

暂无评论

none
暂无评论...