百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分类 > 正文

Python 字符串 DSL 巧计

ztj100 2025-01-12 20:23 17 浏览 0 评论

需求是给字符串加上类似模板语言的支持,比如 'today is current_date' 得到 'today is 2023-02-18' 。

最简单的方式是直接替换,比如下面的实现:

current_date = str(datetime.today().date()))
'today is current_date'.replace('current_date', current_date)

这样不方便扩展,写起来很繁琐,支持的 Function 都需要硬编码实现,而且用户也需要记录这种新造的语法。

这个需求看上去是一个简易的字符串 DSL 实现,比较接近的是 JSON 的 DSL,也很常用,比如 jq 。

一种通用易理解的语法,我想到了 SQL,Python 内置 SQLite,直接在字符串里写 SQL 就好了。

现在只要很少的代码就可以实现这个功能。

import re
import sqlite3
from typing import List, Dict, Any

_PAT = re.compile(r"{{[^{}]*}}")


def run_query(query) -> Dict[str, Any]:
    with sqlite3.connect(":memory:") as connection:
        connection.row_factory = sqlite3.Row
        cursor = connection.cursor()
        try:
            cursor.execute(query)
            row = cursor.fetchone()
        except sqlite3.OperationalError as e:
            raise ValueError(f"Execute query failed: {query}, error: {e}")
        if row:
            return dict(row)
        return dict()


def expression_parse(string) -> List[str]:
    exps = re.findall(_PAT, string)
    return exps


def expression_query(exp):
    function = get_function(exp)
    query = f"SELECT {function} AS result"
    ret = run_query(query)
    if ret:
        return ret["result"]
    raise ValueError(f"Invalid expression: {exp}, result is None")


_alias = {
    "CURRENT_TIME": "time('now', 'localtime')",
    "CURRENT_TIMESTAMP": "unixepoch('now', 'localtime')",
    "CURRENT_DATE": "date('now', 'localtime')",
    "CURRENT_DATETIME": "datetime('now', 'localtime')",
}


def get_function(exp: str):
    function = exp.replace("{", "").replace("}", "").strip()
    function = _alias.get(function.upper(), function)
    return function


def render(string: str):
    """A string containing expressions can be dynamically rendered based on SQLite functions.
    To ensure proper evaluation, expressions must be encapsulated within double curly braces '{{}}'.

    >>> render("s3://landing/appddm_{{date('now', 'localtime')}}/{{strftime('%Y%m%d','now', 'localtime')}}.xlsx")
    's3://landing/appddm_2023-01-16/20230116.xlsx'

    :param string:
    """
    exps = expression_parse(string)
    results = {exp: expression_query(exp) for exp in exps}
    for k, v in results.items():
        string = string.replace(k, str(v))
    return string

Examples:

print(render("s3://bucket/demo.csv"))
print(render("s3://bucket/demo/{{current_date}}.csv"))
print(render("s3://bucket/demo/{{current_datetime}}.csv"))
print(render("s3://bucket/demo/{{current_time}}.csv"))
print(render("s3://bucket/demo/{{current_timestamp}}.csv"))
s = "s3://bucket/demo/{{date('now', 'localtime')}}/{{strftime('%Y%m%d%H%M%S', 'now', 'localtime')}}.xlsx"
print(render(s))
s3://bucket/demo.csv
s3://bucket/demo/2023-02-18.csv
s3://bucket/demo/2023-02-18 22:53:49.csv
s3://bucket/demo/22:53:49.csv
s3://bucket/demo/1676760829.csv
s3://bucket/demo/2023-02-18/20230218225349.xlsx

思考

直接 ast.literal_eval 更简单啊,一开始我没想起来,这当然也可以,不过 SQL 对于非开发者用户更友好,而且直接引用执行 Python 代码的话对用户而言没多少约束,像是个漏洞。

相关推荐

30天学会Python编程:16. Python常用标准库使用教程

16.1collections模块16.1.1高级数据结构16.1.2示例...

强烈推荐!Python 这个宝藏库 re 正则匹配

Python的re模块(RegularExpression正则表达式)提供各种正则表达式的匹配操作。...

Python爬虫中正则表达式的用法,只讲如何应用,不讲原理

Python爬虫:正则的用法(非原理)。大家好,这节课给大家讲正则的实际用法,不讲原理,通俗易懂的讲如何用正则抓取内容。·导入re库,这里是需要从html这段字符串中提取出中间的那几个文字。实例一个对...

Python数据分析实战-正则提取文本的URL网址和邮箱(源码和效果)

实现功能:Python数据分析实战-利用正则表达式提取文本中的URL网址和邮箱...

python爬虫教程之爬取当当网 Top 500 本五星好评书籍

我们使用requests和re来写一个爬虫作为一个爱看书的你(说的跟真的似的)怎么能发现好书呢?所以我们爬取当当网的前500本好五星评书籍怎么样?ok接下来就是学习python的正确姿...

深入理解re模块:Python中的正则表达式神器解析

在Python中,"re"是一个强大的模块,用于处理正则表达式(regularexpressions)。正则表达式是一种强大的文本模式匹配工具,用于在字符串中查找、替换或提取特定模式...

如何使用正则表达式和 Python 匹配不以模式开头的字符串

需要在Python中使用正则表达式来匹配不以给定模式开头的字符串吗?如果是这样,你可以使用下面的语法来查找所有的字符串,除了那些不以https开始的字符串。r"^(?!https).*&...

先Mark后用!8分钟读懂 Python 性能优化

从本文总结了Python开发时,遇到的性能优化问题的定位和解决。概述:性能优化的原则——优化需要优化的部分。性能优化的一般步骤:首先,让你的程序跑起来结果一切正常。然后,运行这个结果正常的代码,看看它...

Python“三步”即可爬取,毋庸置疑

声明:本实例仅供学习,切忌遵守robots协议,请不要使用多线程等方式频繁访问网站。#第一步导入模块importreimportrequests#第二步获取你想爬取的网页地址,发送请求,获取网页内...

简单学Python——re库(正则表达式)2(split、findall、和sub)

1、split():分割字符串,返回列表语法:re.split('分隔符','目标字符串')例如:importrere.split(',','...

Lavazza拉瓦萨再度牵手上海大师赛

阅读此文前,麻烦您点击一下“关注”,方便您进行讨论和分享。Lavazza拉瓦萨再度牵手上海大师赛标题:2024上海大师赛:网球与咖啡的浪漫邂逅在2024年的上海劳力士大师赛上,拉瓦萨咖啡再次成为官...

ArkUI-X构建Android平台AAR及使用

本教程主要讲述如何利用ArkUI-XSDK完成AndroidAAR开发,实现基于ArkTS的声明式开发范式在android平台显示。包括:1.跨平台Library工程开发介绍...

Deepseek写歌详细教程(怎样用deepseek写歌功能)

以下为结合DeepSeek及相关工具实现AI写歌的详细教程,涵盖作词、作曲、演唱全流程:一、核心流程三步法1.AI生成歌词-打开DeepSeek(网页/APP/API),使用结构化提示词生成歌词:...

“AI说唱解说影视”走红,“零基础入行”靠谱吗?本报记者实测

“手里翻找冻鱼,精心的布局;老漠却不言语,脸上带笑意……”《狂飙》剧情被写成歌词,再配上“科目三”背景音乐的演唱,这段1分钟30秒的视频受到了无数网友的点赞。最近一段时间随着AI技术的发展,说唱解说影...

AI音乐制作神器揭秘!3款工具让你秒变高手

在音乐创作的领域里,每个人都有一颗想要成为大师的心。但是面对复杂的乐理知识和繁复的制作过程,许多人的热情被一点点消磨。...

取消回复欢迎 发表评论: