aidlux

官网社区版下载地址 https://community.aidlux.com/aidluxdownload
和termux相比, 更像是一个桌面版Linux. 体积比Termux大很多. 是中国团队开发, 需要手机号登录.
相对Termux来说, Aidlux集成度更高一些, 并且界面上更类似安卓桌面系统, 适合旧手机安装

UserLAnd

https://github.com/CypherpunkArmory/UserLAnd
似乎只是一个虚拟机端, 可以安装不同的linux版本

昨天晚上听了个抖音直播, 里面这个主播老师半夜11点多跟家长讲小孩子应该学什么才有利于以后的升学考试. 家长都可爱听. 其中注意到一个现象,就是大多数家长对编程的兴趣很高, 不停的在问多大年龄应该学编程, 怎么学. 主播简单的说了下乐高不要学, 图形编程不要学, 其他的等下让我讲两分钟其他学科再说. 可结果过了20多分钟也没讲到编程. 感觉主播有意吊着大家胃口. 主播反复说的是英语和编程晚点再讲.
从热度上感觉到编程正在快速在家长身上建立认知.
这里面两个方向:

1. 实物编程/实物代码

现在有几个品牌,但在淘宝上似乎都没有看到销售: 包括
GOBOThttps://show.chinaculture.org/SeeChinesedesign/cn/show-1-537.html
芒果乐联Egobot-少儿实物编程http://imangokid.com/egobot/index.html
"趣思维"实体编程桌面游戏https://www.jianshu.com/p/b76fad1a7c8d
石头村儿童编程益智积木https://www.163.com/dy/article/DEIEJ8S80511A0BH.html
Tangiplayhttps://www.tangiplay.com/?lang=zh
MatataLabhttps://www.sohu.com/a/500505601_121140523
途道编程机器人(积木机器人),淘宝可搜索 https://www.zhihu.com/question/523450964

我觉得在其中又有两点值得注意: 一是玩具化以后, 其实提供了很多可能, 因为玩具可以有很多种形式, 目前还没有固定下来; 二是与机器人的结合. 因为程序必须要操作一个什么东西才行, 机器人/小车就成了最好的载体.
玩具化有好几个的形式其实和lightbot游戏很像, 都是方块指令.

编程教育

这个方向讲了其实好些年, 最早我觉得从邓小平开始了, 在1984年邓小平参观上海一个微电子展的时候说"计算机普及要从娃娃抓起" http://cpc.people.com.cn/n1/2019/1030/c69113-31428714.html. 我记得谭浩强的C程序设计书的前言还提了这句话.
近十年steam教育提出后, 这方面又有很多创业公司, 但似乎都活得不咋样. 我记得四博最早也是做这个创客产品, 没有做下去但倒是积累的技术. 包括seeed(到底几个e😂).最后这些公司能活下来的似乎都是要靠卖芯片,做方案, 做电子产品才行了.
但三年前(2021年)的双减http://www.moe.gov.cn/jyb_xxgk/moe_1777/moe_1778/202107/t20210724_546576.html似乎又给了这个赛道新的机会. 这一次编程似乎作为素质教育之一, 列入了升学类考核了.
目前从各方面资料来看, 是各个学校, 或地方政府先行实施将编程列入中考和高考项目. https://www.sohu.com/a/437728806_99950984

  • 2020年11月25日北京将信息技术(含编程)列入中考范围
  • 2018年, 教育部的新课标将信息技术从兴趣课改为必修课, 并且多个高校给信息技术赛事获得名次的学生加分(这似乎也引起了很多歪风, 变得为竞赛而竞赛, 甚至假竞赛)
  • 2018年, 南京增加了中考的科技特招生
  • 2018年, 浙江省将信息技术作为高考3+7选3的"7选3"之一, 并且多所大学的工科类专业都将信息技术列为必须选考的科目
  • 2022年5月, 《2022年版中小学生信息素养与编程能力测评白皮书》发布
  • 教育部发布《中小学生信息素养提升手册(2024年新版)》,同时许多地市也有自己版本的信息素养提升手册
    我觉得科班出身的体系内的编程教学实力不见得很强,原因是这个与实践结合非常紧密,科班出身的其实缺乏与实践结合的机会,比如编程的最佳实践,软件工程,SCRUM之类对实际非常重要的内容,不做几次项目失败几次是体会不到的。说到项目,我记得似乎有一种项目式学习法,近几年也被提起过。
    下面说下社会方面对编程师资的培养

行业协会的认证和师资培养

我发现主要有三个行业协会,包括中国电子学会、中国软件行业协会、中国计算机学会

中国电子学会 CIE

主要认证是青少年软件编程指导教师证,需要登录后缴费学习.官网https://www.cie.org.cn/ .
并且学会有专门给儿童的考级网站 https://www.qceit.org.cn/bos/default.html

中国软件行业协会 CSIA

官网https://www.csia.org.cn/
这个协会是给企业做双软评定和证书的, 跟企业的关系比较密切.
针对青少年的是NCT考试.

中国计算机学会 CCF

有三种认证, 针对青少年的GESP, 教师资格的PTA, 普通人的CSP

另外, 针对普通人的全国计算机等级考试 NCRE https://ncre.neea.edu.cn/ 是由教育部考试院直接举办的.现在这个考试与时俱进, 下分的门类也是非常丰富了.

通过二级调研,有如下结论:

欧美

收款方面, 欧美国家虽然没有那么强大的移动支付, 不过由于信用卡系统非常发达, 所以在线支付并不是问题.
物流方面, 虽然物流费用比较中国更高,但可靠性可以保证, 也有较好的时效.
品牌方面, 既接受强势的大品牌, 也接受创新的新品牌
增长方面, 近几年电商发展迅速, 增长已经不如前几年迅速, 正在趋于饱和

东南亚

不同国家发展不平衡, 比较有潜力的国家包括印尼(人口最多),马来, 菲律宾, 泰国, 越南,新加坡. 新加坡虽然地方极小,只有1/3个深圳大,但人口有560万, 相当于大半个香港, 而GDP却比香港还高30%左右, 与深圳GDP相当.
其中印尼人口2.7亿, 且出生率几乎是现在中国的两倍, 人口结构比较年轻. 但是人均GDP比较低, 物流不方便.但好在一半人口都居住在JAWA岛上, 物流配送费用较低.
从同样的3C产品height meter(stadiometer)在shopee的马来西亚,印尼,新加坡三站的价格对比来看, 印尼和新加坡支持从国内发货, 产品价格大约是国内的2倍,而印尼产品价格与国内几乎相同.

在阿里的无影云电脑中, 因为安装Uibot Creator无法启动运行, 于是看了下自带的软件商店中有两款RPA软件, 一个是实在RPA,另一个是朗思数字员工. 下载试用感受如下:

实在RPA

跟界面和使用和UiBot有些像的, 相对有这些优势:

  • 基于Python开发, 可视化界面可转为代码界面, 可以看到代码是python形式
  • 新版本有一个IPA模式, 相当于操作录屏, 能加快操作速度(不过Uibot也有录制, 但易用性上差一些)
  • 看其命令菜单,还能操作配套机械臂, 这点很赞
  • 和手机的连接有读取短信功能. 但似乎仅限于此了
    劣势方面:
  • 不能以纯代码方式编辑, 也就是代码界面只能看. 额外的代码需要以插入python代码的方式工作, 或者直接在可视化界面对应的输入框中写. 这样就可能比较别扭, 可视化界面的中文表述有些啰嗦, 而且还不容易看懂.

朗思数字员工

这个界面倒有些像是Blender的节点编辑器, 据说国外的著名UiPath RPA也是类似界面.
优势:

  • 可视化卡片界面
  • 支持微信的操作, 包括信息的读取,发送, 文件发送
  • 支持手机端控制操作
  • 有一些专业化组件, 比如适用于程序员的, 可惜都是企业版才有的功能, 需要付费
    从特别支持微信和手机端操作来看, 朗思的扩展性最强.
    缺点:
  • 并不是所有组件都开放使用, 很多只有企业版才有
  • 没有源码界面, 全部需要通过鼠标点击操作

今天看uibot的时候发现有个友链指向讯鸟软件这家自动化呼叫软件, 其中提到他们可以做BPO外包, 也就看了下什么是BPO外包, 虽然是业务流程外包的简称, 国内似乎和呼叫中心外包几乎等同. 也问了下GPT4还有哪些外包形式. 以下是GPT4的回答.

除了常见的业务流程外包(BPO)和信息技术外包(ITO),还有其他几种服务外包形式,它们根据专业领域的不同而有所区分,包括:

知识过程外包 (KPO) - 这种外包服务涉及更为复杂和专业化的任务,例如法律研究、市场调研、数据分析、高级工程设计等。KPO强调专业知识的深度和复杂性,通常要求服务提供商具有高级专业资格和能力。

法务外包 (LPO) - 法务外包是KPO的一个子集,专注于提供法律相关服务,如合同审核、法律研究、案件管理等。

人力资源外包 (HRO) - 这种外包涉及将人力资源的某些功能或整个HR部门的职责转交给外部服务提供商。常见服务包括员工招聘、薪酬管理、培训与开发等。

工程外包 (EPO) - 工程外包指将工程相关的设计、分析和支持任务交给外部专家。这可以涵盖从机械设计到软件工程等多种领域。

研发外包 (R&D Outsourcing) - 一些公司选择将研发任务外包出去以降低成本并加速产品开发流程。这涉及到科技创新、制药研究以及其它科学和工程领域的任务。

客户支持外包 - 包括呼叫中心服务、技术支持、客户关系管理等。通过外包这些任务,企业能够提供24小时支持,并能使用更多语言来服务全球客户。

这些不同类型的服务外包可以帮助企业更高效地利用全球资源,优化成本结构,并专注于其核心业务领域的发展。

两种模块

  1. 使用命令库, 发布后, 在任何一个项目中使用
  2. 在项目中建一个任务, 直接通过import 任务名导入模块
    我觉得项目少的时候用第二个就好了. 因为第一种命令库的方式似乎总是出错, 并且每次更新很麻烦: 关闭当前项目, 进入命令库项目, 改完代码再发布, 在进入原项目使用. 而方式1直接修改对应任务就完事了, 立即生效.

    使用

    官方对于模块描述比较简单, 主要讲了对模块内的函数使用和模块全局代码的使用.
    以下以建立一个叫tools的模块举例, 在main的任务中调用tools

导入模块

import tools

函数调用

比如其中有一个add(a,b)函数, main中调用方式为
Dim result = tools.add(1,2)

全局代码调用

main中全局代码调用方式:
tools()

官方没讲的, 全局变量和全局代码的返回值

如果在tools模块中定义了一个全局变量Dim g = 1, 这个全局变量会有如下特点:
在main引入了tools并运行了全局代码tools()后, 可以被tools中其他的函数使用, 但不能被main直接调用, 如:

// tools.task
Dim g = 1 
Function getG()
  return g
End Function

// main.task 正确调用方式
import tools
tools()
log.Info(tools.getG()) // 输出1

// main.task 错误调用方式1
import tools
log.Info(tools.getG()) // 输出错误: 名字 g 没有找到. 需要先运行全局代码,才能初始化g

// main.task 错误调用方式2
import tools
tools()
log.Info(tools.g) // 输出错误: 名字 g 没有找到. g已经被初始化但是只能被tools中的函数访问, 类似私有变量

全局代码也可以有返回值, 如

// tools.task
return 10

// main.task
Log.Info(tools()) //打印10

将一个模块当成一个对象来使用

上面的用法暗示了这个tools.task模块可以作为一个对象使用. 其中的全局变量是模块的私有变量, 全局代码是模块的初始化(构造)函数, 模块的函数全部是公有函数. 这个对象不存在公有变量, 需要用类似set/get()公有函数去模拟公有变量. 也没有私有函数. 私有函数可以通过编码规则去模拟, 如前面加下划线_, 外部函数则不要去调用.

很多海外软件下载速度经常只有几个k,这是要用国内镜像下载。从什么莫名其妙的下载站下载担心带毒,可以从华为云下载。

华为云

可以进入其镜像站搜索:
https://mirrors.huaweicloud.com/home
也可以后面直接加软件名

https://mirrors.huaweicloud.com/xxx软件名/
如:
https://mirrors.huaweicloud.com/git-for-windows/
https://mirrors.huaweicloud.com/git-tortoise/
https://mirrors.huaweicloud.com/python/
https://mirrors.huaweicloud.com/nodejs/

阿里云

主要作为库管理器。如python:
pip config set global.index-url https://mirrors.aliyun.com/pypi/simple
nodejs
npm config set registry https://npm.aliyun.com

中国早期的劳动力分配,是按照是否是城镇人口划分的。没有接受教育的农民天生有地,就可以生活。如果经过学习,则可以通过国家分配进入工厂,进而农转非变为市民。根据这篇文章,关于毕业生的分配有如下叙述:

大约在1950年,当时的政务院发出《为有计划地合理地分配全国公私立高等学校今年暑期毕业生工作的通令》,提出对高校毕业生实行有计划的统筹分配;一年之后,再次发布的《关于改革学制的决定》,规定高校毕业生的工作由政府分配。
恢复高考后,国家仍然沿袭了这一规定。1981年,“文革”后的第一批大学生面临毕业之际,国务院批转了原国家计委、国家教委《关于改进1981年普通高等学校毕业生分配工作的报告》,要求对毕业生按照国家统一计划分配:国家教委直属院校毕业生由国家负责面向全国分配;部委主管院校,毕业生由各部委在本系统、本行业内分配;省属院校的毕业生主要由各省市自治区负责面向本地区分配。
建国初期,城镇人口只有一成,到改革开放初期也不到两成。到了去年也就是2023年,城镇人口已经超过65%。这本身导致了城镇就业人口的增加和农村就业人口的减少。如果在经济不景气的时候,意味着城市里分蛋糕的人口会越来越多,人均蛋糕越来越少。而农村人均需要创造的农业产值,却需要越来越高。
而事实上真正的铁饭碗其实只有农民。中国农民靠天(运气)吃饭,但除了给国家交粮,却不存在被压榨,甚至从古代开始自己有地的农民都是如此。所以如果是农民,确实只需要勤劳耕种,就能有收获。而城镇的企业员工除了给国家交税以外,还存在从生存的城市到所在企业的系统性压榨,所以其勤劳程度并不与其收获成正比,因此难以积攒财富。衣食住行成本一直在随着城市人口密度的提升而提升,而贷款买房又透支了员工的未来。而在企业中打工,多数企业往往不愿分享自己的红利给每个员工,反而是制定种种政策来限制员工。这甚至在很多上市企业中也不是个例,比如薪资结构中的工资部分就是城市的最低工资而避免给员工多交保险、加班不给加班工资而提倡员工“奋斗”、在实施双休日多年后依然实施大小周或单休、实施年假制度数年来不给员工批年假、或者仅按城市最低工资标准发放带薪假工资(如果最低工资占比低,相当于多数收入被扣除)、签署竞业协议禁止员工离职后从事本职业……公司通过法律部门规避了自己的各项风险,而员工则不可能改动任何条款,为了工作迫不得已签署的不平等条约式的劳动合同,或者根本不知道合同里面是否给自己埋了坑。在经济上升期,这些矛盾可能还不明显,因为工作岗位是充足的。而在经济不景气甚至不增长的时候,企业都生存困难,就会拿出不平等的合同条款来转嫁自身风险到员工身上。在企业需要人力的时候为企业加班奋斗,在兴冲冲买了房子背了房贷以后被企业一脚踢出大门。再加上AI在这几年快速兴起,可能很快会替代一些岗位,使得就业岗位更加减少。
现在时不时看到一些高学历人士跑美团、跑滴滴、或者自己开小店、摊煎饼、做民宿等等,可能就是一种后果和趋势。

电商有个困扰是发货的时候,对方提供的地址在省市区部分有缺失,自己要查找起来很麻烦。有没有一个方法能直接获取到一个地址的省市区呢?
比较极限的例子就是没有任何省市区,只有一个地名。比如输入深圳北站,返回广东省、深圳市、龙华区。
我猜测地图API应该可以实现。就问了Gemini。回答的答案居然一次性运行成功,没有编码错误。牛!
我用了高德的API,进驻高德开放平台,创建一个应用即可。而且获取省市区的API只需要KEY就行,没有复杂的鉴权过程。属于“地里编码”类型,每日调用限额5000次。

Gemini回答

以下 API 能够根据地址字符串返回省、市、区:

API 使用方法

高德地图开放平台

GET https://restapi.amap.com/v3/geocode/geo?address=深圳北站&key={{高德地图API Key}}

百度地图开放平台

GET https://api.map.baidu.com/geocoding/v3/?address=深圳北站&output=json&ak={{百度地图API Key}}

API 返回数据示例

高德地图开放平台

{
  "count": 1,
  "info": "OK",
  "infocode": "10000",
  "geocodes": [
    {
      "formatted_address": "广东省深圳市龙华区梅林街道龙胜社区万丰路一号",
      "adcode": "440306",
      "country": "中国",
      "province": "广东省",
      "city": "深圳市",
      "district": "龙华区",
      "township": "梅林街道"
    }
  ]
}

百度地图开放平台

{
  "status": "OK",
  "result": {
    "address": "深圳北站东广场",
    "location": {
      "lat": 22.60116700193512,
      "lng": 114.06170188547761
    },
    "precise": 1,
    "confidence": 70,
    "level": "地铁站",
    "formatted_address": "广东省深圳市龙华区梅林街道龙胜社区万丰路一号(近深圳北站东广场)",
    "business": [],
    "poiRegions": [],
    "semg": [],
    "adname": "广东省深圳市龙华区"
  }
}

示例代码

Python 示例(基于高德地图开放平台)

import requests

def get_address_info(address_string):
    url = "https://restapi.amap.com/v3/geocode/geo"
    params = {
        "address": address_string,
        "key": "YOUR_GAODE_API_KEY"  # 替换为你的高德地图 API Key
    }
    response = requests.get(url, params=params)
    data = response.json()
    if data["info"] == "OK":
        return data["geocodes"][0]["province"], data["geocodes"][0]["city"], data["geocodes"][0]["district"]
    else:
        return None

address_info = get_address_info("深圳北站")
print(address_info)  # 输出:('广东省', '深圳市', '龙华区')

一般月份简写都是3个字母.我感觉2个字母也足以简写.
jan/feb/mar/apr/may/jun/jul/aug/oct/nov/dec
jn/fb/mr/ap/my/jn/jl/ag/oc/nv/dc

不知道为什么没有人这么总结过.

  • 食: 饮食, 能量来源.
  • 泄: 排泄, 有吃有喝有排泄, 吸收有用的排出有毒的.
  • 息: 气息, 呼吸. 但这一点绝大多数时候是无意识进行的, 不需要意识控制.
  • 温: 温度, 维持人体温度.
  • 眠: 睡眠.
  • 色: 性需求.
    呼吸因为自发自主, 空气又是免费的, 不需要成本. 所以如果讨论是否必须要去有意识付出代价获取的话, 通常可以排除. 余下食泄温眠色.
    老祖宗说食色性也, 包括了食和色. 又说衣食住行, 包括了温食眠. 又说吃喝拉撒, 包括了食泄.
    不过, 从重视程度来说, 食肯定排在第一位的, 温也就是衣可以排在第二位, 这两个都是参与社交, 并作为社交的一部分的, 而且食本身作为社交手段, 又最常用作拉进相互关系. 眠排在第三位, 它不参与社交, 而且直到现代电光源发明之前, 睡眠时长都不存在问题. 泄和色讲起来都颇为忌讳, 其中泄排在第四位, 因为虽然忌讳, 但也从未被禁止过, 而色排在最后一位, 因为不但忌讳, 而且在历史上不断地被各种花式禁止.
    这个问题我问了GPT4, 从其回答顺序和爽快程度上, 也可以看出下面的排位.

我: 请总结对人生存所需要的最基本的生理需求, 包括那几点, 每一点分别用一个汉字来概括.

GPT4: 对人生存所需要的最基本的生理需求通常可以概括为以下几点:

  1. - 人体大部分由水构成,维持身体功能必须要有足够的水分。
  2. - 获取足够的营养包括蛋白质、脂肪、碳水化合物、维生素和矿物质。
  3. - 呼吸新鲜空气来供给身体必需的氧气用于细胞的代谢活动。
  4. - 保持适宜的体温, 既不能过热也不能过冷。
  5. - 充足的睡眠对恢复体力和精神都是必要的。
    这些是人类生存最基础的生理需求。

我: 是否还遗漏了其他方面
GPT4: 我的回答中确实遗漏了其他一些基本生理需求。除了水、食、氧、温和睡之外,还应该包括:
6. - 排泄体内积累的废物和毒素,维持身体的正常功能。
7. - 避险本能,即寻求安全,躲避危险和威胁来保护自己不受伤害。
这些基本生理需求综合起来,构成了人类生存必需的条件。

我: 是否还有遗漏
GPT4: 在以上所述的基本生理需求(水、食、氧、温、睡、排)之外,可以再补充一项基本生理需求:
7. - 生物学上的性需求,涉及繁殖和种族延续。
这七项基础构成了人类生存的核心生理需求。

所以GPT4显然也是受到人类文化熏陶, 总是不肯把所有的关键点一次性说出来.

如果页面使用了shadow-root, 在shadow-root节点以下, 无法使用querySelector进行选择. 这也会导致绝大多数的页面爬虫无法爬取数据, 如chrome插件instant data scraper以及uibot的数据抓取功能. 比如微信的后台都是使用shadow-root的. 个人感觉shadow-root是iframe的一种更优雅的替代技术.

e = $('micro-app') // 选择shadowRoot节点, 可以在开发者工具中看到下面标有#shadow-root(open)的
e.shadowRoot.querySelector('your-css-selector') // 此时就可以选择了

以下代码可以运行. 意味着可以使用回调函数

Function f1(x,y)
    return x + y
end Function
Function f2(x,y)
    return x - y 
End Function
Function a(f)
    Log.Info(f(1,2))
End Function
a(f1)
a(f2)

并且函数名除了作为形参,还可以作为普通变量以及对象的值

Dim f = f2
f('from f')

dim o = {
    'f': f1
}
dim o_f = o['f']
o_f('from o_f')

Function f1(s)
    Log.Info('f1')
    Log.Info(s)
End Function

Function f2(s)
    Log.Info('f2')
    Log.Info(s)

End Function

上面的用法,意味着可以创造类似于接口的功能,使用同一接口函数抽象调用,实际实现可以不同。
另外,也可以实现类似于面向对象的开发,在一个object中除了定义变量还可以定义函数。只是在对象中的函数不能直接写在对象里,也不能匿名,需要在外面写好,在对象里赋值。
同样的,对象里的函数也不能通过o['f']()的方式调用,需要先赋值给变量,再通过变量调用。

另外,发现在函数中使用这种方法会报错,似乎和编译有关:

Function a()
  dim f = f1
  f()
End Function

Function f1()
  log.info(f1)
End Function

报错: 后端错误 unexpected symbol near ')'
这种情况只要将dim f放到全局就会正常,不知道为何,似乎是回调函数名称必须为全局变量(常量), 如下:

dim f
Function a()
  f = f1
  f()
End Function

Function f1()
  log.info(f1)
End Function

另外,始终没有找到根据字符串常量表示的函数名调用对应函数的方法。

回调的坑: 跨文件调用回调会丢失全局环境(包括全局变量)

有一个主文件为test.task, 一个作为提供函数的模块文件tools.task, 如果在主文件中调用模块文件中的函数, 并给其提供的回调函数位于主文件中, 那么此回调函数不能访问主文件中的全局变量.
调用关系: 主文件->调用模块文件的函数(主文件的回调函数名)->调用主文件回调函数->丢失主文件全局变量. 示意如下:

/* tools.task 模块文件 */
Function funcInTools(cb)
    Log.Info('funcInTools')
    gCallback = cb
    gCallback()
End Function

/* test.task 主文件 */
Import tools
Dim gCallback
Dim gLost = 11 
funcInMain(cbInMain) // 通过主文件的函数调用主文件的回调函数, 不会丢失全局变量
tools.funcInTools(cbInMain) // 通过模块文件的函数调用主文件的回调函数, 丢失全局变量

Function cbInMain() //主文件中的回调
    Log.Info(gLost)
End Function

Function funcInMain(cb)
    Log.Info('funcInMain')
    gCallback = cb
    gCallback()
End Function

运行后输出如下:

[2024-4-24 11:42:04] [INFO] 流程 test.task 开始运行
[2024-4-24 11:42:04] [INFO] test.task 第15行:funcInMain
[2024-4-24 11:42:04] [INFO] test.task 第11行:11
[2024-4-24 11:42:04] [INFO] tools.task 第7行:funcInTools
[2024-4-24 11:42:04] [INFO] test.task 第11行:null

可以看到回调函数第一次调用可以输出全局变量, 而第二次调用则不可以.
这种情况建议将全局变量通过形参传入:

/* tools.task 模块文件 */
Function funcInTools(cb, 传入变量)
    Log.Info('funcInTools')
    gCallback = cb
    gCallback(传入变量)
End Function

/* test.task 主文件 */
Import tools
Dim gCallback
Dim gLost = 11 
tools.funcInTools(cbInMain, gLost) // 通过模块文件的函数调用主文件的回调函数, 丢失全局变量

Function cbInMain(传入变量) //主文件中的回调
    Log.Info(传入变量)
End Function

python中有cpca库, 可以匹配省市区并返回. 但这个库有些老, 好多年不更新, 像深圳龙华区这些近几年升级为区的都没有. 所以需要结合正则实现.
python还有另外一个geopy库也可以实现, 但是这个库需要实时通过API读取, 还总是timeout, 所以放弃这个方案.
UiBot本来支持python扩展来解决, 但是不知为何Uibot自带的python对cpca支持有问题, 始终报错, 所以放弃, 改为Uibot调用系统命令读取打印输出的方式曲线救国.
python代码都是GPT4 Turbo写的, 自己做了小修改.
Uibot测试:

PyTools('parse_address', '广东省深圳市龙华区深圳北站')

Uibot函数:

// 由于通过uibot的python调用存在问题(import cpca始终报错), 所以通过命令行调用
// python路径直接写在tools.bat中, 使用系统where python给出的路径, 避免uibot调用错误的python版本. 此时在系统中使用Pip安装的库可以直接在这儿使用
// tools.bat直接调用执行tools.py. 具体函数在tools.py中实现
// 以Json字符串形式返回
Function PyTools(func, params)
    // params支持单字符串的单参数或者数组形式的多参数
    Dim Ret
    If type('params') = 'string'
        Ret = Sys.Command(@res"tools.bat "+func+" "+params)
    else
        Dim cmd = @res"tools.bat "+func
        For Each p In params 
            cmd = cmd + " " + p
        Next
        Ret = Sys.Command(@res"tools.bat "+func+cmd)
    End if 
    return JSON.Parse(Ret)
End Function

系统命令 tools.bat和python脚本tools.py, 放在uibot项目的res目录下. 如果不放心调用哪个版本的python,可以积极在python前面加路径.

@echo off
python.exe D:\folder\to\project\res\tools.py %1 %2 %3 %4 %5 %6 %7 %8 %9
@echo on

tool.py部分. 大多数是gpt4写的

# tools.py

import sys,re,json
import cpca

def parse_address(address):
    a = ""
    a1 = parse_address1(address)
    a2 = parse_address2(address)
    # 策略: 长度相同优选a1方法, 否则选a2
    if len(a2) <= len(a1):
        a = a1
    else:
        a = a2
    # return f"{a[0]}|{a[1]}|{a[2]}"
    return json.dumps(a, ensure_ascii=False)

# 采用cpca获取省市区. 好处: 不写省市区这几个字都能识别. 问题: 可能有数据库过期问题(龙华区无法识别)
def parse_address1(address):
    # 使用 cpca 库解析地址并返回 DataFrame
    df = cpca.transform([address])
    location = df.iloc[0]  # 提取第一行数据,即我们需要的地址解析结果

    # 返回省市区字符串,用 "|" 分隔
    # return f"{location['省']}|{location['市']}|{location['区']}"
    return list(filter(None,[location['省'], location['市'], location['区']]))

# 采用正则表达式获取省市区. 好处: 不需要更新数据库. 问题: 必须有省市区这几个字.
def parse_address2(address):
    # 更新省/直辖市的匹配模式以处理没有“市”字的直辖市情况
    pattern = re.compile(
        r'(?P<province>[^省]+省|[^自治区]+自治区|北京|天津|上海|重庆)?'
        r'(?P<city>[^市]+市|[^自治州]+自治州|[^地区]+地区|[^盟]+盟)?'
        r'(?P<district>[^县]+县|[^区]+区|[^旗]+旗|[^自治县]+自治县|[^林区]+林区|[^特别行政区]+特别行政区)?'
    )
    match = pattern.search(address)
    if not match:
        return "无法提取地址信息"

    province, city, district = match.group('province', 'city', 'district')

    # 北京、天津、上海和重庆作为直辖市,如果匹配到省份但没有匹配到市,将省份的名字赋给城市
    if province in ['北京', '天津', '上海', '重庆'] and not city:
        city = province
        city = city + '市'

    # 如果没有匹配到,则用空字符串代替
    province = province if province else ''
    city = city if city else ''
    district = district if district else ''

    # 以"|"连接非空字符串
    # result = '|'.join(filter(None, [province, city, district]))

    return list(filter(None,[province, city, district]))

def test_parse_address():
    print(parse_address('广东省深圳市龙华区深圳北站'))


if __name__ == "__main__":
    if len(sys.argv) < 3:
        print("Usage: python tools.py parse_address 'Your Address String Here'")
        sys.exit(1)
    if sys.argv[1] == "parse_address":
        input_address = sys.argv[2]
        result = parse_address(input_address)
        print(result)
    elif sys.argv[1] == "test_parse_address":
        test_parse_address()
    else:
        print('["没有正确的函数名"]')