通过python过滤数据中的emoji特殊字符

代码  ·  2024-10-30

一、背景介绍

在数据开发过程中任务要求将数据由数据湖将数据推送至MySQL数据库。数据类型大多是字符串类型。原本没有什么特别,属于常规任务。但是在推送是由于字符集的问题,无法正常推送。

1. 对应工具

数据湖 Hive
下游数据库 MySQL
传输工具 DataX

二、所遇问题

数据湖所支持的字符集为 udf8mb4,而下游mysql数据库所支持的 udf-8。由于 udf8mb4 是 udf-8 的扩展集。即 udf8mb4 范围大于 udf-8 ,且数据中包含emoji表情超出 udf-8 所支持范围。所以导致数据无法正常传输。
报错:

java.sql.BatchUpdateException: Conversion from collation utf8mb4_0900_ai_ci into utf8_general_ci impossible for parameter

三、解决方案

1. 方案一(不适用):

最直接的方法也是网上大多的处理办法:改下游mysql的字符集。
但是首先需要判断mysql版本是否支持utf8mb4。如果您的 MySQL 版本太低,无法支持 utf8mb4_0900_ai_ci,那么您可以考虑升级 MySQL 版本到 8.0.0 或更高版本。
特别提示需要将MySQL配置中的字符集全部修改。

character_set_client utf8mb4 
character_set_connection utf8mb4 
character_set_database utf8mb4 
character_set_filesystem binary 
character_set_results utf8mb4 
character_set_server utf8mb4 
character_set_system utf8mb3

即以上所示配置都需要修改。
踩坑:我的需求是将数据从数据湖hive推送至MySQL,所以必然会用到MySQL服务。但是在修改MySQL服务后会涉及服务重启,由于涉及到其他业务部门的调用,需要多方协调。太麻烦啦!故此方法不可取。

2. 方案二(采用):

经与业务同事沟通,由于utf8mb4大多为emoji表情包,且包含此内容的数据条数较少。故通过将脏数据(数据中包含utf8mb4集字符)过滤掉的方法解决问题。

判断是否为emoji字符

def is_emoji_character(char):
    # 这是一个非常简化的检查,只涵盖了部分Emoji范围
    # 实际的Emoji检测可能需要更复杂的逻辑或使用第三方库
    code_point = ord(char)
    # 检查是否在某个Emoji范围内(这里只是示例,不是完整的范围)
    # 例如,U+1F600 到 U+1F64F 是常见的Emoji范围之一
    return 0x1F600 <= code_point <= 0x1F64F or \
        0x1F300 <= code_point <= 0x1F5FF or \
        0x1F680 <= code_point <= 0x1F6FF or \
        0x1F700 <= code_point <= 0x1F77F or \
        0x1F780 <= code_point <= 0x1F7FF or \
        0x1F800 <= code_point <= 0x1F8FF or \
        0x1F900 <= code_point <= 0x1F9FF or \
        0x1FA00 <= code_point <= 0x1FA6F or \
        0x1FA70 <= code_point <= 0x1FAFF  # ... 可以添加更多范围

定位对应数据并输出到其他表中

def check_for_emoji():
    cur = datalake_connect()
    # 数据日期为前一天
    etl_date='${biz.date,-1,yyyy-MM-dd}'
    
    selectsql1 = "select id,title,source_id,text,text_nohtml from mytable1 where  etl_date='%s' " % (etl_date)
    print(selectsql1)
    news = cur.sql(selectsql1).collect()
    
    if news:
    # 获得行数据
        for value in news:
            # print(value)
            contains_emoji = False
            # 获得字段字段数据
            for check_string in value:
                if check_string is None:
                    continue
                for check_char in check_string:
                    try:
                        if is_emoji_character(check_char):
                            contains_emoji = True
                            break  # 如果只需要知道是否存在Emoji,找到后就可以退出循环
                    except Exception as e:
                        print(check_char)
                        print(e)
                if contains_emoji:
                    break
            if contains_emoji:
                print("是一个包含emoji的字符串"+value[0])
                insertsql2 = "insert into mytable2 values('%s','%s','%s','%s')"%(value[0],value[1],value[2],etl_date)
                print(insertsql2)
                news = cur.sql(insertsql2)
            else:
                print("是一个不包含emoji的字符串"+value[0])
    else:
        print("数据日期没有数据;结束!")

注:内涵特殊数据库执行方法可忽略
通过以上方法可以将包含emoji的数据输出到其他的表2中,后续根据表2所存id过滤数据。则可以将非emoji数据推送至下游数据库了。

 
评论
博闻广记. All Rights Reserved. Theme Jasmine by Kent Liao.