Compare commits

...

10 Commits

Author SHA1 Message Date
张育新
a2dbd51f35 Merge branch 'main' of https://github.com/OSHMKUFA5100/lab
# Conflicts:
#	note/随手记/go.md
2026-08-06 09:15:15 +08:00
张育新
241a7c43da docs(note): 新增 excel/正则/Nginx 笔记并整理目录
- 新增 AGENTS.md 仓库说明与 excelize 依赖
- 新增正则表达式、go操作excel、Nginx常见错误、Golang底层架构笔记
- 布尔变量命名迁移至资源/编程/规范,删除随手记旧笔记
2026-08-05 18:32:17 +08:00
张育新
735a339deb test(regularMatch): 添加中文正则匹配测试 2026-08-05 18:31:59 +08:00
b6063cb9f9 docs(go): 添加内存逃逸学习笔记与示例代码
- 新增 go/basics/MemoryEscape/main.go,演示返回局部变量指针和闭包引用两种典型逃逸场景
- 在 note/随手记/go.md 中补充内存逃逸的概念、影响、常见原因及逃逸分析命令
- 清理 note/随手记/网址.md 中的多余空行
2026-07-23 00:07:16 +08:00
张育新
ef18635509 docs(note): 补充技术笔记和主题配置
- Go map Swiss Table 实现说明
- MarkText 仿 onelight 暗色主题
- 布尔变量命名规范
- 更新网址收藏及跟踪 assets 资源
2026-07-21 17:53:15 +08:00
张育新
3819ae9d94 Merge branch 'main' of https://github.com/OSHMKUFA5100/lab 2026-07-15 19:14:20 +08:00
张育新
e486d47e2a docs(note): reorganize notes structure and migrate content
- Move Windows and 算法 notes from 随手记 to 资源 directory
- Migrate Golang map pitfalls and dot import notes to Golang/使用注意
- Delete omos配置 note
- Add Typora custom theme reference link
2026-07-15 19:12:07 +08:00
e6fe90a7c0 Merge branch 'main' of https://github.com/OSHMKUFA5100/lab 2026-07-13 23:12:38 +08:00
f870a1b224 test(slice): 添加 slice append 行为测试
新增 go/testing/slice/slice_test.go,验证将 slice 作为参数传入函数并在函数内 append 时不会影响原 slice 的 len/cap,借此说明 slice 值传递时的扩容行为。
2026-07-13 23:12:02 +08:00
张育新
e00245ea66 docs(note): 补充 git merge --abort 取消合并命令 2026-07-13 22:46:30 +08:00
21 changed files with 960 additions and 233 deletions

1
.gitignore vendored
View File

@ -30,5 +30,4 @@ build/
Thumbs.db
# ---- Note 目录 ----
note/assets/
note/项目/

36
AGENTS.md Normal file
View File

@ -0,0 +1,36 @@
# AGENTS.md
## 仓库结构
按语言分层的个人练习仓库,每种语言一个顶层目录,各自独立管理依赖。
| 目录 | 说明 |
|---|---|
| `go/` | Go module `lab`Go 1.26.2go.mod 在该目录内 |
| `note/` | 个人笔记(非代码),`note/项目/` 被 gitignore |
| `dart/` | 预留,尚未建立 |
## Go 约定
- **Module 在 `go/` 目录下,不在仓库根**——所有 go 命令需在 `go/` 内执行
- 每个叶子目录 = 一个独立小程序(`package main` + `main.go`
- 多个小程序可并存,不同目录、各自独立
- 主题目录basics/concurrency/stdlib/patterns/algorithms/web/testing/project可随时增删
- 测试文件用 `*_test.go`,运行单个测试:`cd go && go test ./testing/ -run TestSliceAppend`
## 开发命令
```
# Go——所有命令在 go/ 目录下执行
cd go
go run ./<主题>/<程序名>/ # 运行单个程序
go test ./... # 运行全部测试
go test ./testing/ -v # 运行 testing 包测试
go mod tidy # 整理依赖
```
## 注意事项
- 仓库无 CI、无 pre-commit hooks、无代码检查——每个程序自行保证可编译即可
- 笔记和练习代码严格分离:程序相关说明写在程序目录的 README.md系统性知识放 `note/`
- `.gitignore` 已覆盖 Go 二进制、Dart/Flutter 构建产物、IDE 配置、操作系统文件

View File

@ -0,0 +1,25 @@
package main
import (
"fmt"
)
type User struct {
Name string
}
func NewUser() *User {
u := User{}
return &u
}
func ClosureFunc() func() int {
a := 1
return func() int {
return a
}
}
func main() {
fmt.Println(NewUser())
cf:= ClosureFunc()
fmt.Println(cf())
}

View File

@ -1,3 +1,15 @@
module lab
go 1.26.2
require (
github.com/richardlehane/mscfb v1.0.7 // indirect
github.com/richardlehane/msoleps v1.0.6 // indirect
github.com/tiendc/go-deepcopy v1.7.2 // indirect
github.com/xuri/efp v0.0.1 // indirect
github.com/xuri/excelize/v2 v2.11.0 // indirect
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 // indirect
golang.org/x/crypto v0.53.0 // indirect
golang.org/x/net v0.56.0 // indirect
golang.org/x/text v0.38.0 // indirect
)

18
go/go.sum Normal file
View File

@ -0,0 +1,18 @@
github.com/richardlehane/mscfb v1.0.7 h1:oeoiM0WE79vHwE8RpIYYvIAc8ajTH2mb6UZm55/+EB0=
github.com/richardlehane/mscfb v1.0.7/go.mod h1:pe0+IUIc0AHh0+teNzBlJCtSyZdFOGgV4ZK9bsoV+Jo=
github.com/richardlehane/msoleps v1.0.6 h1:9BvkpjvD+iUBalUY4esMwv6uBkfOip/Lzvd93jvR9gg=
github.com/richardlehane/msoleps v1.0.6/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
github.com/tiendc/go-deepcopy v1.7.2 h1:Ut2yYR7W9tWjTQitganoIue4UGxZwCcJy3orjrrIj44=
github.com/tiendc/go-deepcopy v1.7.2/go.mod h1:4bKjNC2r7boYOkD2IOuZpYjmlDdzjbpTRyCx+goBCJQ=
github.com/xuri/efp v0.0.1 h1:fws5Rv3myXyYni8uwj2qKjVaRP30PdjeYe2Y6FDsCL8=
github.com/xuri/efp v0.0.1/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
github.com/xuri/excelize/v2 v2.11.0 h1:HxaEFl6sRN2+8J5a8HaKq+0M4FsjBGMnWWtjOCPSG88=
github.com/xuri/excelize/v2 v2.11.0/go.mod h1:jxFLbzaIwGQ5ufFNvYfUOHqXhfPaNmP14KWfmNz2Uak=
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 h1:+C0TIdyyYmzadGaL/HBLbf3WdLgC29pgyhTjAT/0nuE=
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto=
golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio=
golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=

View File

@ -0,0 +1,21 @@
package regularmatch
import (
"regexp"
"testing"
)
func TestChineseRegExp(t *testing.T) {
reg, err := regexp.Compile("[\u4e00-\u9fa5]")
if err != nil {
t.Errorf("Failed to compile regex: %v", err)
}
matchStrSlice := reg.FindAllString("hello 世界", -1)
if len(matchStrSlice) != 2 {
t.Errorf("Expected 2 matches, got %d", len(matchStrSlice))
}
if matchStrSlice[0] != "世" || matchStrSlice[1] != "界" {
t.Errorf("Expected [世, 界], got %v", matchStrSlice)
}
}

View File

@ -0,0 +1,18 @@
package main
import (
"fmt"
"testing"
)
func appendSlice(s []int, n int) {
s = append(s, n)
fmt.Printf("len=%d,cap=%d\n", len(s), cap(s))
}
func TestSliceAppend(t *testing.T) {
s1 := make([]int, 5)
appendSlice(s1, 10)
if len(s1) != 5 || cap(s1) != 5 {
t.Errorf("Expected len=5, cap=5; got len=%d, cap=%d", len(s1), cap(s1))
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

View File

@ -35,11 +35,12 @@
#### 四、合并与变基
| 操作 | 命令 | 说明 |
| -------------- | ------------------------------------ | ------------------------- |
| 合并分支 | `git merge feature/xxx` | 把目标分支合并进当前分支 |
| 变基rebase | `git rebase dev` | 让你的提交在最新 `dev` 上 |
| 解决冲突后继续 | `git add . && git rebase --continue` | 继续变基或合并流程 |
| 操作 | 命令 | 说明 |
| -------------- | ------------------------------------ | ------------------------------- |
| 合并分支 | `git merge feature/xxx` | 把目标分支合并进当前分支 |
| 取消合并 | `git merge --abort` | 终止合并,直接回退到合并前的状态 |
| 变基rebase | `git rebase dev` | 让你的提交在最新 `dev` 上 |
| 解决冲突后继续 | `git add . && git rebase --continue` | 继续变基或合并流程 |
#### 五、查看状态和差异

View File

@ -0,0 +1,45 @@
## Nginx 反代未透传客户端 IP 导致服务端日志全量变为 127.0.0.1
### 现象
后端解析IP后全量变成 `127.0.0.1`
### 原因
后端解析IP的顺序是
```
X-Forwarded-For → X-Real-IP → RemoteAddr
```
**Nginx**转发至后端服务的 location 块缺少`proxy_set_header`指令:
```nginx
location /olive3 {
proxy_pass http://127.0.0.1:55430;
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
}
```
### 修复
在缺失的 location 块中补充 header 透传:
```nginx
location /api {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://127.0.0.1:55430;
# ... 其他配置不变
}
```
- `$proxy_add_x_forwarded_for`:将客户端真实 IP 追加到已有 `X-Forwarded-For` 尾部,而非覆盖
- `$remote_addr`Nginx 直接看到的对端地址,作为 `X-Real-IP` 传递

View File

@ -14,4 +14,5 @@
### 拖拽到终端
- 直接把文件**拖入** PowerShell 或 CMD 窗口,会自动粘贴完整路径。
- 直接把文件**拖入** PowerShell 或 CMD 窗口,会自动粘贴完整路径。

View File

@ -210,3 +210,54 @@ func TestJson(t *testing.T) {
1. **小请求配置、JSON**:使用 `io.ReadAll` 存入内存,再通过 `io.NopCloser` 塞回 `r.Body` 或设置 `r.GetBody`
2. **中等请求(签名校验)**:使用 `io.TeeReader` 边读边处理,节省一次全量扫描。
3. **大请求(文件上传)****禁止 ReadAll**。直接流式 `io.Copy` 到目的地,或使用临时文件做中转。
## map的坑
go的map内部是哈希表元素会因 rehash扩容而移动到新的内存位置如果允许 `&m[key]` 拿到一个指针map 一旦扩容,这个指针就变成悬空指针(指向已失效的内存),为了避免这种内存安全问题Go 直接禁止对 map 值取地址,下面是示例代码:
```go
type User struct {
Name string
Age int
}
func main() {
m := map[int]User{1: {Name: "张三", Age: 20}}
// ❌ 编译错误cannot assign to struct field m[1].Name in map
m[1].Name = "李四"
// ✅ 正确的替代写法
temp:=m[1]
temp.Name = "李四"
m[1]=temp
}
```
> **可寻址addressable**:能通过 `&` 拿到它内存地址的操作数。
>
> **不可寻址not addressable**:不能通过 `&` 拿到地址的操作数。
## 句点引入
一个完整引入声明语句形式的引入名`importname`可以是一个句点(`.`)。 这样的引入称为句点引入。使用被句点引入的包中的导出代码要素时,限定标识符的前缀必须省略。
比如在下面这个例子中,`Println`和`Now`函数调用不需要带任何前缀。
```go
package main
import (
. "fmt"
. "time"
)
func main() {
Println("Current time:", Now())
}
```
> 一般来说,句点引入不推荐使用,因为它们会导致较低的代码可读性

View File

@ -0,0 +1,73 @@
Go 1.24 起,`map` 的底层实现从传统的 `hmap` + `bmap` 哈希表,彻底切换到了 Swiss Table瑞士表
![Gemini_Generated_Image_jhqwi7jhqwi7jhqw](D:\zhangyuxin\code\lab\note\assets\golang-map[swiss table].png)
### Group内存布局图
你可以直接复制以下文本块到你的 Markdown 笔记中(使用 text 包裹):
codeText
```
+-------------------------------------------------------------------------------+
| 单 Group 内存布局 |
+--------------------------+----------------------------+-----------------------+
| 1. Metadata 控制字节区 | 2. 连续 Key 存储区 | 3. 连续 Value 存储区 |
+--------------------------+----------------------------+-----------------------+
| [M0][M1][M2]...[M7] | [K0][K1][K2]...[K7] | [V0][V1][V2]...[V7] |
+--------------------------+----------------------------+-----------------------+
| <- 固定 8 个字节 -> | <- 长度取决于 Key 类型 -> | <- 长度取决于 Val -> |
| <- 一次性载入寄存器对比 -> | |
```
**为什么这样设计?(设计优势):**
1.
2. **避免内存对齐填充Padding**:如果采用 [Meta][Key][Value] 交叉排列,由于不同类型的 Key/Value 字节大小不同为了对齐Go 必须在它们之间插入大量空白填充字节,浪费空间。分块连续存储消除了组内的对齐损耗。
3. **对 CPU 缓存友好**8 字节的 Metadata 紧密相连,一次 Cache Line 填充就能把整组的控制信息全部读入,极大地提高了缓存命中率。
------
### 读取流程
以下为您整理的完整、正确的读取逻辑,您可以直接复制使用:
#### 1.哈希计算与分段 (Hash Splitting)
- 将 Key 传入哈希函数,计算出一个 **64 位的哈希值**
- 该哈希值被拆分为两部分:**H1高 57 位)**:用于定位哈希表中的初始 Group 索引。**H2低 7 位)**:作为特征值(指纹),存储在 Group 的 Metadata 中,用于快速匹配。
#### 2.定位初始 Group (Locate Group)
- 计算初始 Group 索引group_index = H1 & (Group数量 - 1)。
> 可以理解与$2^B$进行取模运算,但是**位与运算**效率更高且等价。
#### 3.组内快速匹配 (Group-level SWAR Match)
- **一次性加载**:将目标 Group 的 8 字节 Metadata 一次性载入一个 64 位寄存器中。
- **并行对比SWAR 技术)**:利用位运算,将 7 位的 H2 同时与这 8 个 Metadata 字节进行并行对比,输出一个 8 位的位掩码Bitmask。位掩码中为 1 的位,代表该位置的 H2 与目标 H2 匹配成功。这一步极快,完全避免了循环遍历。
#### 4.冲突解决与探测循环 (Verification & Probing Loop)
根据位掩码的匹配结果,执行以下逻辑:
1. 依次根据匹配成功的索引,去 **Key 存储区** 找到对应的真实 Key。
2. 进行完整的 Key 等值对比(如 if key == targetKey**若匹配成功**:直接去 **Value 存储区** 对应偏移量取出 Value 并返回。**若匹配失败**:说明发生了 **H2 哈希冲突**(即不同的 Key 产生了相同的 H2继续对比下一个匹配的槽位。
3. 如果当前 Group 中所有匹配了 H2 的槽位都对比完了,仍未找到匹配的 Key则**跳转至【情况 B】**。
此时需要检查当前 Group 的 Metadata 状态,决定是继续向后寻找还是停止:
- **若当前 Group 中存在“空位”Empty0xFF**
说明探测链在此处断开,该 Key 在 Map 中**一定不存在**,直接返回 nil 或零值。
- **若当前 Group 中无空位但存在“墓碑”Tombstone0x80或已满**
虽然当前 Group 没找到,但可能因为历史删除操作(留下了墓碑)或哈希冲突,导致数据被存到了后续的 Group。不能停止使用**二次探测算法Quadratic Probing**计算下一个 Group 的索引,跳转回 **【3.组内快速匹配】** 继续循环寻找。

View File

@ -0,0 +1,17 @@
## 命名规则
> [《布尔变量起名的艺术》](https://thatamazingprogrammer.com/posts/stop-naming-your-variables-flag-the-art-of-boolean-prefixes/)
### 使用正确的前缀
1**is**:描述事物的状态,后面跟形容词,比如 isActiveisDeletedisEmpty。
2**has**:描述事物的所有权或包含关系,后面跟名词,比如 hasAccesshasChildrenhasValidationErrors。
3**can**:描述事物的能力或权限,比如 canEditcanDeletecanRetry。
4**should**:描述事物的意图或逻辑,比如 shouldRetryshouldCacheResponse。
### 其他
永远不在布尔变量名中使用否定词比如isDisabled因为当使用在if语句中会让大脑进行双重否定运算

View File

@ -1,50 +0,0 @@
## 句点引入
一个完整引入声明语句形式的引入名`importname`可以是一个句点(`.`)。 这样的引入称为句点引入。使用被句点引入的包中的导出代码要素时,限定标识符的前缀必须省略。
比如在下面这个例子中,`Println`和`Now`函数调用不需要带任何前缀。
```go
package main
import (
. "fmt"
. "time"
)
func main() {
Println("Current time:", Now())
}
```
> 一般来说,句点引入不推荐使用,因为它们会导致较低的代码可读性
## map的坑
go的map内部是哈希表元素会因 rehash扩容而移动到新的内存位置如果允许 `&m[key]` 拿到一个指针map 一旦扩容,这个指针就变成悬空指针(指向已失效的内存),为了避免这种内存安全问题Go 直接禁止对 map 值取地址,下面是示例代码:
```go
type User struct {
Name string
Age int
}
func main() {
m := map[int]User{1: {Name: "张三", Age: 20}}
// ❌ 编译错误cannot assign to struct field m[1].Name in map
m[1].Name = "李四"
// ✅ 正确的替代写法
temp:=m[1]
temp.Name = "李四"
m[1]=temp
}
```
> **可寻址addressable**:能通过 `&` 拿到它内存地址的操作数。
>
> **不可寻址not addressable**:不能通过 `&` 拿到地址的操作数。

View File

@ -0,0 +1,83 @@
## excelize库
读写Excel的Go库
[github](https://github.com/qax-os/excelize)
## 基本用法
### 创建工作簿
```go
f := excelize.NewFile()
defer func() {
if err := f.Close(); err != nil {
fmt.Println(err)
}
}()
// 创建一个新的Sheet,返回的index为该工作簿的索引
index, err := f.NewSheet("SheetName")
if err != nil {
return fmt.Errorf("创建Sheet失败: %w", err)
}
```
### 打开文件
```go
f, err := excelize.OpenFile(filePath)
if err != nil {
return fmt.Errorf("打开 Excel失败: %w", err)
}
defer func() {
if err := f.Close(); err != nil {
fmt.Println(err)
}
}()
```
### 写入cell值
```go
f.SetCellValue("SheetName", "B2", 100)
```
### 设置工作簿默认活动工作表
```go
f.SetActiveSheet(index)
```
### 创建或更新excel表
```go
if err := f.SaveAs("Book1.xlsx"); err != nil {
return fmt.Errorf("保存失败: %w", err)
}
```
### 获取指定cell值
```go
cell, err := f.GetCellValue("Sheet1", "B2")
if err != nil {
return fmt.Errorf("读取cell失败: %w", err)
}
fmt.Println(cell)
```
### 获取所有工作簿的cell值二维数组
```go
rows, err := f.GetRows("Sheet1")
if err != nil {
return fmt.Errorf("读取失败: %w", err)
}
for _, row := range rows {
for _, colCell := range row {
fmt.Print(colCell, "\t")
}
fmt.Println()
}
```

View File

@ -1,176 +0,0 @@
```json
{
"$schema": "https://unpkg.com/oh-my-opencode-slim@latest/oh-my-opencode-slim.schema.json",
"preset": "zhipu",
"presets": {
"opencode-go": {
"orchestrator": {
"model": "opencode-go/glm-5.2",
"skills": [
"*"
],
"mcps": [
"*",
"!context7"
]
},
"oracle": {
"model": "deepseek/deepseek-v4-pro",
"variant": "max",
"skills": [
"simplify"
],
"mcps": []
},
"council": {
"model": "opencode-go/qwen3.7-max",
"variant": "high",
"skills": [],
"mcps": []
},
"librarian": {
"model": "opencode-go/minimax-m3",
"skills": [],
"mcps": [
"websearch",
"context7",
"gh_grep"
]
},
"explorer": {
"model": "opencode-go/mimo-v2.5-pro",
"skills": [],
"mcps": []
},
"designer": {
"model": "opencode-go/kimi-k2.7-code",
"variant": "medium",
"skills": [],
"mcps": []
},
"fixer": {
"model": "opencode-go/deepseek-v4-flash",
"variant": "high",
"skills": [],
"mcps": []
},
"observer": {
"model": "opencode-go/kimi-k2.7-code",
"skills": [],
"mcps": []
}
},
"zhipu": {
"orchestrator": {
"model": "zhipuai-coding-plan/glm-5.2",
"skills": [
"*"
],
"mcps": [
"*",
"!context7"
]
},
"oracle": {
"model": "zhipuai-coding-plan/glm-5.2",
"variant": "max",
"skills": [
"simplify"
],
"mcps": []
},
"council": {
"model": "zhipuai-coding-plan/glm-5.1",
"skills": [],
"mcps": []
},
"librarian": {
"model": "zhipuai-coding-plan/glm-5-turbo",
"skills": [],
"mcps": [
"websearch",
"context7",
"gh_grep"
]
},
"explorer": {
"model": "zhipuai-coding-plan/glm-5-turbo",
"skills": [],
"mcps": []
},
"designer": {
"model": "zhipuai-coding-plan/glm-5.2",
"variant": "medium",
"skills": [],
"mcps": []
},
"fixer": {
"model": "zhipuai-coding-plan/glm-5.2",
"skills": [],
"mcps": []
},
"observer": {
"model": "zhipuai-coding-plan/glm-4.6v",
"skills": [],
"mcps": []
}
},
"deepseek": {
"orchestrator": {
"model": "deepseek/deepseek-v4-pro",
"variant": "high",
"skills": [
"*"
],
"mcps": [
"*",
"!context7"
]
},
"oracle": {
"model": "deepseek/deepseek-v4-pro",
"variant": "max",
"skills": [
"simplify"
],
"mcps": []
},
"council": {
"model": "deepseek/deepseek-v4-pro",
"variant": "medium",
"skills": [],
"mcps": []
},
"librarian": {
"model": "deepseek/deepseek-v4-flash",
"skills": [],
"mcps": [
"websearch",
"context7",
"gh_grep"
]
},
"explorer": {
"model": "deepseek/deepseek-v4-flash",
"skills": [],
"mcps": []
},
"designer": {
"model": "deepseek/deepseek-v4-pro",
"variant": "medium",
"skills": [],
"mcps": []
},
"fixer": {
"model": "deepseek/deepseek-v4-flash",
"variant": "high",
"skills": [],
"mcps": []
}
}
},
"disabled_agents": []
}
```

View File

@ -0,0 +1,476 @@
> 感觉还是不如typora好使啊,以后买个正版吧
```css
/**
* MarkText One Light Dark 主题 (仿 Typora onelight-darkhttps://github.com/caolib/typora-onelight-theme)
*
* 使用方法:
* 在 MarkText 中打开 设置 → 主题 → 自定义 CSS
* 将本文件全部内容粘贴进去,保存即可。
*
* 配色来源: Typora onelight-dark theme by caolib
* 兼容: MarkText v0.19.x (旧引擎) / v0.20+ (新引擎)
*/
/* ====================================================================
* CSS 变量 — 使用 camelCase 命名 (旧引擎 v0.19.x 兼容)
* ==================================================================== */
:root {
/* —— 编辑器核心 —— */
--themeColor: #5c99f3;
--themeColor90: rgba(92, 153, 243, 0.9);
--themeColor80: rgba(92, 153, 243, 0.8);
--themeColor70: rgba(92, 153, 243, 0.7);
--themeColor60: rgba(92, 153, 243, 0.6);
--themeColor50: rgba(92, 153, 243, 0.5);
--themeColor40: rgba(92, 153, 243, 0.4);
--themeColor30: rgba(92, 153, 243, 0.3);
--themeColor20: rgba(92, 153, 243, 0.2);
--themeColor10: rgba(92, 153, 243, 0.1);
--highlightThemeColor: #e94ab9;
--highlightColor: #ffffff10;
--selectionColor: #3266d0;
--editorColor: #c3c3c3;
--editorColor80: #c3c3c3;
--editorColor60: rgba(195, 195, 195, 0.6);
--editorColor50: rgba(195, 195, 195, 0.5);
--editorColor40: rgba(195, 195, 195, 0.4);
--editorColor30: rgba(195, 195, 195, 0.3);
--editorColor10: rgba(195, 195, 195, 0.1);
--editorColor04: rgba(195, 195, 195, 0.04);
--editorBgColor: #1f1f1e;
--editorAreaWidth: 900px;
--deleteColor: #ff6b6b;
--iconColor: rgba(195, 195, 195, 0.56);
--codeBgColor: #282c34;
--codeBlockBgColor: #282c34;
--footnoteBgColor: rgba(51, 51, 51, 0.5);
--inputBgColor: #3d404e;
--focusColor: #5c99f3;
/* —— 按钮 —— */
--buttonFontColor: #c3c3c3;
--buttonBgColor: #333333;
--buttonBorder: 1px solid #353a45;
--buttonShadow: none;
--buttonFontColorHover: #ffffff;
--buttonBgColorHover: #414855;
--buttonBorderHover: var(--buttonBorder);
--buttonFontColorActive: var(--buttonFontColor);
--buttonBgColorActive: #2a2d35;
--buttonBorderActive: var(--buttonBorder);
--buttonFocusBorder: 1px solid #5c99f3;
--buttonFocusShadow: 0 0 0 1px rgba(92, 153, 243, 0.3);
--buttonPrimaryFontColor: #ffffff;
--buttonPrimaryBgColor: #5c99f3;
--buttonPrimaryBorder: 1px solid #4a8ad9;
--buttonPrimaryShadow: none;
--buttonPrimaryFontColorHover: var(--buttonPrimaryFontColor);
--buttonPrimaryBgColorHover: #4a8ad9;
--buttonPrimaryBorderHover: var(--buttonPrimaryBorder);
--buttonPrimaryFontColorActive: var(--buttonPrimaryFontColor);
--buttonPrimaryBgColorActive: #3d7bc4;
--buttonPrimaryBorderActive: var(--buttonPrimaryBorder);
--buttonPrimaryFocusBorder: none;
--buttonPrimaryFocusShadow: inset 0 0 0 1px rgba(24, 26, 31, 0.5), 0 0 0 1px #5c99f3;
/* —— Markdown 元素 —— */
--headingColor: #c3c3c3;
--h1Color: #c3c3c3;
--h2Color: #c3c3c3;
--h3Color: #c3c3c3;
--h4Color: #ffffff;
--h5Color: #c3c3c3;
--h6Color: #c3c3c3;
--blockquoteTextColor: rgba(195, 195, 195, 0.8);
--blockquoteBorderColor: #5c99f3;
--hrColor: #5c99f3;
--linkColor: #e94ab9;
--strongColor: #5c99f3;
--emColor: #e94ab9;
--listMarkerColor: #5c99f3;
--tableBorderColor: #393e49;
/* —— 侧边栏 —— */
--sideBarColor: #c3c3c3;
--sideBarIconColor: var(--iconColor);
--sideBarTitleColor: #c3c3c3;
--sideBarTextColor: #7a7a7a;
--sideBarBgColor: #1f1f1e;
--sideBarItemHoverBgColor: #333333;
--itemBgColor: #333333;
/* —— 浮动层 —— */
--floatFontColor: #c3c3c3;
--floatBgColor: #353a45;
--floatHoverColor: #414855;
--floatBorderColor: #353a45;
--floatShadow: rgba(0, 0, 0, 0.3);
--maskColor: rgba(0, 0, 0, 0.7);
}
/* ====================================================================
* 全局背景 — 统一为 Typora onelight-dark 底色 #1f1f1e
* ==================================================================== */
html, body {
background-color: #1f1f1e;
}
.editor-wrapper {
background-color: #1f1f1e;
}
.editor-component {
background-color: #1f1f1e;
}
#ag-editor-id {
background-color: #1f1f1e;
}
/* ====================================================================
* 滚动条
* ==================================================================== */
::-webkit-scrollbar,
::-webkit-scrollbar-corner {
background: var(--editorBgColor);
}
::-webkit-scrollbar:vertical { width: 8px; }
::-webkit-scrollbar:vertical:hover { width: 10px; }
::-webkit-scrollbar-thumb {
background: rgba(134, 134, 134, 0.27);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(255, 255, 255, 0.5);
}
/* ====================================================================
* 弹窗 (Element UI)
* ==================================================================== */
.v-modal { background: #08090a !important; opacity: 0.65 !important; }
.el-dialog,
.el-dialog.ag-dialog-table {
border-radius: 6px !important;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3) !important;
border: 1px solid #353a45 !important;
background: #2a2a29 !important;
}
.el-button:focus { color: var(--buttonFontColor); }
.el-button--primary:focus {
color: var(--buttonPrimaryFontColor);
background: var(--buttonPrimaryBgColor);
}
/* ====================================================================
* 标题栏 / 浮动菜单
* ==================================================================== */
.title-bar .frameless-titlebar-button > div > svg { fill: #c3c3c3; }
.title-bar .frameless-titlebar-minimize:hover,
.title-bar .frameless-titlebar-toggle:hover {
background-color: rgba(195, 195, 195, 0.05) !important;
}
.input-wrapper {
border-radius: 5px !important;
border: 1px solid #353a45 !important;
background: #2a2a29 !important;
}
.ag-front-menu,
.ag-float-wrapper {
box-shadow: 0 4px 8px 0 var(--floatShadow) !important;
}
/* ====================================================================
* 侧边栏
* ==================================================================== */
.side-bar { border-right: 1px solid #333333 !important; }
.left-column ul > li > svg { fill: rgba(195, 195, 195, 0.6) !important; }
.left-column ul > li:hover > svg { fill: #ffffff !important; }
.left-column ul > li.active > svg { fill: #5c99f3 !important; }
/* ====================================================================
* 标签栏
* ==================================================================== */
.editor-tabs {
box-shadow: none !important;
background: var(--editorBgColor) !important;
}
.editor-tabs:after {
position: absolute;
content: '';
border-bottom: 1px solid #333333;
bottom: 0; left: 0; right: 0; z-index: 1;
}
.editor-tabs ul.tabs-container:after {
position: absolute;
content: '';
border-bottom: 1px solid #333333;
bottom: 0; left: 0; right: 0; z-index: 2;
}
.tabs-container > li,
.tabs-container > li.active { background: var(--editorBgColor) !important; }
.tabs-container > li.active {
border: 1px solid #333333;
border-bottom: none;
}
.tabs-container > li.active:after {
top: 0 !important; right: auto !important;
width: 2px !important; height: auto !important;
background: #5c99f3 !important;
}
.tabs-container svg.close-icon #unsaved-circle-icon { fill: #5c99f3; }
/* ====================================================================
* 编辑器内容区 (v0.19.x 旧引擎: 容器是 #ag-editor-id)
* ==================================================================== */
/* ---- 标题 ---- */
#ag-editor-id h1 {
text-align: center;
padding-bottom: 0.3em;
}
#ag-editor-id h2 {
border-bottom: 2px solid var(--themeColor);
}
#ag-editor-id h3 {
border-left: 4px solid var(--themeColor);
padding-left: 8px;
}
#ag-editor-id h4 {
color: #ffffff !important;
background: var(--themeColor);
border-radius: 5px;
width: fit-content;
padding: 2px 12px;
}
/* ---- 粗体 / 斜体 ---- */
#ag-editor-id strong { color: var(--strongColor); font-weight: 700; }
#ag-editor-id em { color: var(--emColor); }
/* ---- 链接 ---- */
#ag-editor-id a {
color: var(--linkColor);
font-weight: 700;
text-decoration: underline;
}
/* ---- 行内代码 ---- */
#ag-editor-id code {
background-color: var(--codeBlockBgColor);
color: #eb4c37;
border-radius: 3px;
padding: 2px 4px;
}
/* ---- 代码块 ---- */
#ag-editor-id :not(pre) > code[class*='language-'],
#ag-editor-id pre:not(.CodeMirror-line),
#ag-editor-id pre[class*='language-'],
#ag-editor-id pre.ag-paragraph {
background: var(--codeBlockBgColor) !important;
border: none !important;
border-radius: 5px !important;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
transition: box-shadow 0.3s ease;
}
/* ---- 引用块 (四面边框 + 左侧加粗) ---- */
#ag-editor-id blockquote {
padding: 10px 10px 10px 20px;
font-size: 0.9em;
border: 2px solid var(--blockquoteBorderColor);
border-left: 5px solid var(--blockquoteBorderColor);
border-radius: 0 5px 5px 0;
background: transparent;
overflow: auto;
transition: background-color 0.3s ease, box-shadow 0.3s ease;
}
#ag-editor-id blockquote:hover {
background: var(--editorBgColor);
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
}
/* 隐藏引擎默认的 ::before 竖条,改用 border-left */
#ag-editor-id blockquote::before {
content: none;
}
/* ---- 分割线 ---- */
#ag-editor-id hr {
height: 2px;
background-color: var(--hrColor);
}
/* ---- 表格 ---- */
#ag-editor-id table tr th::before,
#ag-editor-id table tr td::before {
border-color: var(--tableBorderColor);
}
/* ---- 图片 ---- */
#ag-editor-id img {
border-radius: 10px;
display: block;
margin: 0 auto;
max-width: 100%;
}
/* ---- 任务列表复选框 ---- */
#ag-editor-id li.ag-task-list-item {
list-style-type: none;
position: relative;
}
#ag-editor-id li.ag-task-list-item > input[type='checkbox'] {
position: absolute;
cursor: pointer;
width: 16px; height: 16px; top: 0.1em;
margin: 0; left: -24px;
transform-origin: center;
transition: all 0.2s ease;
appearance: none;
-webkit-appearance: none;
}
#ag-editor-id li.ag-task-list-item > input[type='checkbox']::before {
content: '';
width: 16px; height: 16px;
box-sizing: border-box;
display: inline-block;
border: 2px solid var(--editorColor50);
border-radius: 2px;
background-color: var(--editorBgColor);
position: absolute; top: 0; left: 0;
transition: all 0.2s ease;
}
#ag-editor-id li.ag-task-list-item > input[type='checkbox']:checked::before {
border-color: transparent;
background-color: var(--themeColor);
}
#ag-editor-id li.ag-task-list-item > input[type='checkbox']::after {
content: '';
transform: rotate(-45deg) scale(0);
width: 9px; height: 5px;
border: 2px solid #fff;
border-top: none; border-right: none;
position: absolute; display: inline-block;
top: 1px; left: 5px;
transition: all 0.2s ease;
}
#ag-editor-id li.ag-task-list-item > input[type='checkbox']:checked::after {
transform: rotate(-45deg) scale(1);
}
/* ---- 段落悬停 ---- */
#ag-editor-id p.ag-paragraph {
padding: 5px;
margin: 0;
border-radius: 5px;
transition: background-color 0.3s ease, box-shadow 0.3s ease;
}
#ag-editor-id p.ag-paragraph:hover {
background: #141414;
box-shadow: 0 4px 4px rgba(0, 0, 0, 0.3);
}
/* ---- 已完成任务文字 ---- */
#ag-editor-id li.ag-task-list-item > input.ag-checkbox-checked ~ * {
color: var(--editorColor50);
}
/* ---- 列表标记 ---- */
#ag-editor-id ul > li::marker,
#ag-editor-id ol > li::marker {
color: var(--listMarkerColor);
}
/* ---- 搜索高亮 ---- */
.ag-highlight {
background: #ff0 !important;
color: red !important;
border-radius: 3px;
padding: 0 2px;
height: auto !important;
line-height: inherit !important;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}
/* ---- 表格表头 ---- */
#ag-editor-id table tr th {
background: var(--editorColor04);
}
#ag-editor-id table tr:first-child td {
background: var(--editorColor04);
}
/* ---- 脚注 ---- */
#ag-editor-id sup.md-footnote {
color: var(--strongColor);
font-weight: 700;
}
/* ---- 前置图标 ---- */
.ag-front-icon {
fill: var(--editorColor30);
}
/* ====================================================================
* CodeMirror 源码模式 (v0.19.x 旧引擎)
* ==================================================================== */
.source-code {
background: var(--editorBgColor);
}
.source-code .CodeMirror {
color: var(--editorColor);
background: transparent;
}
.source-code .CodeMirror-gutters {
background: transparent;
border-right-color: #333333;
}
.source-code .CodeMirror-linenumber {
color: var(--editorColor30);
}
.source-code .CodeMirror-cursor {
border-left-color: var(--themeColor);
}
.source-code .CodeMirror-activeline-background {
background: var(--editorColor04);
}
.source-code .CodeMirror-selected {
background: var(--selectionColor) !important;
}
/* CodeMirror 语法高亮色 — 参考 onelight 配色 */
.cm-s-one-dark .cm-comment { color: #7f848e; font-style: italic; }
.cm-s-one-dark .cm-keyword { color: #c678dd; }
.cm-s-one-dark .cm-operator { color: #56b6c2; }
.cm-s-one-dark .cm-builtin { color: #e5c07b; }
.cm-s-one-dark .cm-atom { color: #d19a66; }
.cm-s-one-dark .cm-number { color: #d19a66; }
.cm-s-one-dark .cm-def { color: #61afef; }
.cm-s-one-dark .cm-string { color: #98c379; }
.cm-s-one-dark .cm-string-2 { color: #e06c75; }
.cm-s-one-dark .cm-variable { color: #e06c75; }
.cm-s-one-dark .cm-variable-2 { color: #e5c07b; }
.cm-s-one-dark .cm-variable-3 { color: #d19a66; }
.cm-s-one-dark .cm-type { color: #e5c07b; }
.cm-s-one-dark .cm-meta { color: #e06c75; }
.cm-s-one-dark .cm-attribute { color: #d19a66; }
.cm-s-one-dark .cm-property { color: #e06c75; }
.cm-s-one-dark .cm-qualifier { color: #e5c07b; }
.cm-s-one-dark .cm-tag { color: #e06c75; }
.cm-s-one-dark .cm-link { color: #c678dd; }
.cm-s-one-dark .cm-header { color: #61afef; }
.cm-s-one-dark .cm-quote { color: #98c379; }
/* ====================================================================
* Mermaid/图表 SVG 暗色适配
* ==================================================================== */
figure[data-role] svg rect[fill='#ffffff'] { fill: var(--editorBgColor); }
figure[data-role] svg rect[stroke='#000000'] { stroke: var(--editorColor); }
figure[data-role] svg text[fill='#000000'] { fill: var(--editorColor); }
figure[data-role] svg path[stroke='#000000'] { stroke: var(--editorColor); }
figure[data-role] svg path[fill='#ffffff'] { fill: var(--editorBgColor); }
figure[data-role] svg path[fill='#000000'] { fill: var(--editorColor); }
figure[data-role] svg use[fill='black'] { fill: var(--editorColor); }
figure[data-role] svg use[fill='#000000'] { fill: var(--editorColor); }
```

View File

@ -0,0 +1,72 @@
# 正则表达式
正则表达式是一种用于匹配和操作文本的强大工具,用于描述要匹配的文本模式。
## 匹配字符
### 普通匹配字符
| 字符 | 描述 |
| :------- | :----------------------------------------------------------- |
| `[xyz]` | 匹配 `[xyz]` 中列出的所有字符。例如 `[xyz]`,能够匹配目标的所有 x、y、z 字符。 |
| `[^xyz]` | 匹配 `[^xyz]` 中列出的字符外的所有字符。例如 `[^xyz]`,能够匹配目标的除去 x、y、z 外的所有字符。 |
| `[A-Z]` | `[A-Z]` 表示一个区间,匹配所有大写字母;`[a-z]` 匹配所有小写字母;`[0-9]` 匹配所有数字。 |
| `[\s\S]` | 匹配所有字符(包括换行符)。`\s` 匹配所有空白符(包括换行),`\S` 匹配所有非空白符(不包括换行),两者合并即可匹配任意字符。 |
| `.` | 匹配除换行符 `\n`、`\r` 之外的任何单个字符,等价于 `[^\n\r]`。 |
| `\w` | 匹配字母、数字、下划线,等价于 `[A-Za-z0-9_]`。 |
| `\d` | 匹配任意一个阿拉伯数字0 到 9等价于 `[0-9]`。 |
### 非打印字符
| 字符 | 描述 |
| :---- | :----------------------------------------------------------- |
| `\cx` | 匹配由 x 指明的控制字符。例如,`\cM` 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一,否则将 c 视为一个原义的 'c' 字符。 |
| `\f` | 匹配一个换页符,等价于 `\x0c``\cL`。 |
| `\n` | 匹配一个换行符,等价于 `\x0a``\cJ`。 |
| `\r` | 匹配一个回车符,等价于 `\x0d``\cM`。 |
| `\s` | 匹配任何空白字符,包括空格、制表符、换页符等,等价于 `[ \f\n\r\t\v]`。注意 Unicode 正则表达式会匹配全角空格符。 |
| `\S` | 匹配任何非空白字符,等价于 `[^ \f\n\r\t\v]`。 |
| `\t` | 匹配一个制表符,等价于 `\x09``\cI`。 |
| `\v` | 匹配一个垂直制表符,等价于 `\x0b``\cK`。 |
### 特殊字符
| 特殊字符 | 描述 |
| :------- | :----------------------------------------------------------- |
| `$` | 匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 `$` 也匹配 `\n``\r`。要匹配 `$` 字符本身,请使用 `\$`。 |
| `( )` | 标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 `\(``\)`。 |
| `*` | 匹配前面的子表达式零次或多次。要匹配 `*` 字符本身,请使用 `\*`。 |
| `+` | 匹配前面的子表达式一次或多次。要匹配 `+` 字符本身,请使用 `\+`。 |
| `.` | 匹配除换行符 `\n` 之外的任何单字符。要匹配 `.` 本身,请使用 `\.`。 |
| `[` | 标记一个中括号表达式的开始。要匹配 `[`,请使用 `\[`。 |
| `?` | 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 `?` 字符本身,请使用 `\?`。 |
| `\` | 将下一个字符标记为特殊字符、原义字符、向后引用或八进制转义符。例如,`\\` 匹配 `\`。 |
| `^` | 匹配输入字符串的开始位置。在方括号表达式中使用时,表示不接受方括号内的字符集合(取反)。要匹配 `^` 字符本身,请使用 `\^`。 |
| `{` | 标记限定符表达式的开始。要匹配 `{`,请使用 `\{`。 |
| `|` | 指明两项之间的一个选择。要匹配 `|`,请使用 `\|`。 |
### 限定符
| 字符 | 描述 |
| :------ | :----------------------------------------------------------- |
| `*` | 匹配前面的子表达式零次或多次。 |
| `+` | 匹配前面的子表达式一次或多次。 |
| `?` | 匹配前面的子表达式零次或一次,等价于 `{0,1}`。例如,`do(es)?` 可以匹配 "do" 和 "does",但不能匹配 "dog"。 |
| `{n}` | n 是一个非负整数,匹配确定的 n 次。例如,`o{2}` 不能匹配 "Bob" 中的 o但是能匹配 "food" 中的两个 o。 |
| `{n,}` | n 是一个非负整数,至少匹配 n 次。例如,`o{2,}` 不能匹配 "Bob" 中的 o但能匹配 "foooood" 中的所有 o。`o{1,}` 等价于 `o+``o{0,}` 等价于 `o*`。 |
| `{n,m}` | m 和 n 均为非负整数,其中 n <= m。最少匹配 n 次且最多匹配 m 次。例如,`o{1,3}` 将匹配 "fooooood" 中的前三个 o。`o{0,1}` 等价于 `o?`。 |
## 常用正则表达式
| 正则表达式 | 匹配内容 |
| -------------------------- | ---------- |
| `[\u4e00-\u9fa5]` | 中文字符 |
| `\d{3}-\d{8}|\d{4}-\{7,8}` | 国内手机号 |
| | |
| | |
| | |
| | |
| | |
| | |
| | |

View File

@ -1,4 +1,9 @@
[Typora onelight 主题](https://github.com/caolib/typora-onelight-theme?tab=readme-ov-file#4%E5%85%B3%E4%BA%8E%E5%AD%97%E4%BD%93)
[Typora自定义主题](https://theme.typora.io/doc/zh/Write-Custom-Theme/)
> 通过自定义的CSS变量来实现
[CSDN增强助手](https://chromewebstore.google.com/detail/csdn%E5%A2%9E%E5%BC%BA%E5%8A%A9%E6%89%8B/fpgaealcfgjbodghojppfmohfcoajled)
> 能够智能屏蔽CSDN搜索结果、屏蔽其广告、自动展开代码