Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
CSDN 技术社区
skill_tree_dotnet
提交
f92f0c16
S
skill_tree_dotnet
项目概览
CSDN 技术社区
/
skill_tree_dotnet
通知
30
Star
6
Fork
4
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
2
列表
看板
标记
里程碑
合并请求
1
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
S
skill_tree_dotnet
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
2
Issue
2
列表
看板
标记
里程碑
合并请求
1
合并请求
1
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
f92f0c16
编写于
1月 22, 2022
作者:
幻灰龙
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'encoding' into 'master'
Encoding See merge request
!3
上级
b7ce0d39
403f3779
变更
14
隐藏空白更改
内联
并排
Showing
14 changed file
with
120 addition
and
526 deletion
+120
-526
.pre-commit-config.yaml
.pre-commit-config.yaml
+6
-0
data/1..NET初阶/2.C#语法/3.C#字符串格式设置/StringFormatting.md
data/1..NET初阶/2.C#语法/3.C#字符串格式设置/StringFormatting.md
+40
-38
data/1..NET初阶/3.C#特性/1.C#3.0特性/AnonymousType.md
data/1..NET初阶/3.C#特性/1.C#3.0特性/AnonymousType.md
+8
-8
data/1..NET初阶/3.C#特性/1.C#3.0特性/AutoImplementedProperties.md
data/1..NET初阶/3.C#特性/1.C#3.0特性/AutoImplementedProperties.md
+6
-6
data/1..NET初阶/3.C#特性/1.C#3.0特性/ExpressionTree.md
data/1..NET初阶/3.C#特性/1.C#3.0特性/ExpressionTree.md
+9
-9
data/1..NET初阶/3.C#特性/1.C#3.0特性/ExtensionMethod.md
data/1..NET初阶/3.C#特性/1.C#3.0特性/ExtensionMethod.md
+6
-6
data/1..NET初阶/3.C#特性/1.C#3.0特性/LambdaExpression.md
data/1..NET初阶/3.C#特性/1.C#3.0特性/LambdaExpression.md
+6
-6
data/1..NET初阶/3.C#特性/1.C#3.0特性/QueryExpression.md
data/1..NET初阶/3.C#特性/1.C#3.0特性/QueryExpression.md
+12
-12
data/1..NET初阶/3.C#特性/1.C#3.0特性/config.json
data/1..NET初阶/3.C#特性/1.C#3.0特性/config.json
+9
-1
data/2..NET中阶/1.ASP.NET Core应用/4.Web API应用/WebAPI.md
data/2..NET中阶/1.ASP.NET Core应用/4.Web API应用/WebAPI.md
+12
-12
data/2..NET中阶/1.ASP.NET Core应用/4.Web API应用/config.json
data/2..NET中阶/1.ASP.NET Core应用/4.Web API应用/config.json
+4
-1
main.py
main.py
+1
-1
requirement.txt
requirement.txt
+1
-1
src/tree.py
src/tree.py
+0
-425
未找到文件。
.pre-commit-config.yaml
0 → 100644
浏览文件 @
f92f0c16
repos
:
-
repo
:
git@codechina.csdn.net:csdn/skill_tree_hook.git
rev
:
8cb76ab3b493582d3dab0021fb6fddfa28ec5a66
hooks
:
-
id
:
pre-commit
verbose
:
true
\ No newline at end of file
data/1..NET初阶/2.C#语法/3.C#字符串格式设置/StringFormatting.md
浏览文件 @
f92f0c16
#
在C#中执行基本字符串格式设置
#
在C#中执行基本字符串格式设置
System.String是一个类,专门用于存储字符串,允许对字符串进行许多操作。由于这种数据类型非常重要,C#提供了它自己的关键字和相关的语法,以便于使用这个类来轻松地处理字符串。 String源码网址: https://referencesource.microsoft.com/#mscorlib/system/string.cs
System.String是一个类,专门用于存储字符串,允许对字符串进行许多操作。由于这种数据类
型非常重要,C#提供了它自己的关键字和相关的语法,以便于使用这个类来轻松地处理字符串。
String 源码网址: https://referencesource.microsoft.com/#mscorlib/system/string.cs
使用运算符重载可以连接字符串
:
使用运算符重载可以连接字符串:
```
csharp
string
message1
=
"Hello"
;
// return "Hello"
...
...
@@ -10,34 +12,34 @@ message1 += ", CodeChina"; // return "Hello, CodeChina"
string
message2
=
message1
+
"!"
;
//return "Hello, CodeChina!"
```
C#
还允许使用类似于索引器的语法来提取指定的字符
:
C#
还允许使用类似于索引器的语法来提取指定的字符:
```
csharp
string
message1
=
"Hello"
;
char
char1
=
message
[
1
]
// return 'e'
```
这个类可以完成许多常见的任务,如替换字符、删除空白和把字母变成大写形式等等。可用的方法如下表所示(此表并不完整,只介绍部分字符串提供的常用功能)。
这个类可以完成许多常见的任务,如替换字符、删除空白和把字母变成大写形式等等。可用的方法如下表所示(此表并不完整,只介绍部分字符串提供的常用功能)。
|
方法|作用
|
|
方法|作用|
|----|----|
|Compare|
比较字符串的内容,判断某些字符是否相等|
|Concat |
把多个字符串实例合并为一个实例|
|Format |
格式化包含各种值的字符串和如何格式化每个值的说明符|
|IndexOf|
定位字符串中第一次出现某个给定子字符串或字符的位置|
|Insert |
把一个字符串实例插入到另一个字符串实例的指定索引处
|
|Join |
合并字符串数组,创建一个新字符串|
|PadLeft|
在字符串的左侧,通过添加指定的重复字符填充字符串
|
|Replace|
用另一个字符或子字符串替换字符串中给定的字符或子字符串
|
|Split |
在出现给定字符的地方,把字符串拆分为一个字符串数组
|
|Substring|
在字符串中检索给定位置的子字符串
|
|ToLower|
把字符串转换为小写形式|
|ToUpper|
把字符串转换为大写形式|
|Trim |
删除首位的空白|
>
注意如果Format想要输出'{'或'}',请这样s
tring.Format("{{Hello}}");
除了这些方法C#还提供了'@'和'$',@是可以忽略字符串的转义,$是可以把代码插到字符串中。
|Compare|
比较字符串的内容,判断某些字符是否相等|
|Concat |
把多个字符串实例合并为一个实例|
|Format |
格式化包含各种值的字符串和如何格式化每个值的说明符|
|IndexOf|
定位字符串中第一次出现某个给定子字符串或字符的位置|
|Insert |
把一个字符串实例插入到另一个字符串实例的指定索引处|
|Join |
合并字符串数组,创建一个新字符串|
|PadLeft|
在字符串的左侧,通过添加指定的重复字符填充字符串|
|Replace|
用另一个字符或子字符串替换字符串中给定的字符或子字符串|
|Split |
在出现给定字符的地方,把字符串拆分为一个字符串数组|
|Substring|
在字符串中检索给定位置的子字符串|
|ToLower|
把字符串转换为小写形式|
|ToUpper|
把字符串转换为大写形式|
|Trim |
删除首位的空白|
>
注意如果Format想要输出'{'或'}',请这样string
.Format("{{Hello}}");
除了这些方法C#还提供了'@'和'$',@是可以忽略字符串的转义,$是可以把代码插到字符串中。
```
csharp
int
count
=
6
;
...
...
@@ -45,9 +47,9 @@ string str1 = $"6{count}6"; // return "666"
string
str2
=
@"6\r6\n6"
;
//return "6\r6\n6"
```
以下程序中,不能使str3等于
`"Hello, CodeChina!"`
的是:
以下程序中,不能使str3等于
`"Hello, CodeChina!"`
的是:
##
答案
##
答案
```
csharp
var
str1
=
"Hello, "
;
...
...
@@ -55,7 +57,7 @@ var str2 = "CodeChina!";
var
str3
=
"str1"
+
"str2"
;
```
##
选项
##
选项
### A
...
...
@@ -81,26 +83,26 @@ var str2 = "CodeChina!";
var
str3
=
string
.
Concat
(
str1
,
str2
);
```
|
格式说明符|应用|含义|示例
|
|
格式说明符|应用|含义|示例|
|----------|----|----|----|
|C|
数字类型|特定地区的货币值|
$666.00|
|D|
用于数字类型|一般的整数
|666|
|E|
数字类型|科学计数法|
6.660000E+002|
|F|
数字类型|小数点后的位数固定|
666.00|
|G|
数字类型|一般的数字
|666|
|N|
数字类型|通常是特定地区的数字格式
|666.00|
|P|
数字类型|百分比计数法
|66,600.00%|
|X|
只用于整数类型|十六进制格式
|29A|
|C|
数字类型|特定地区的货币值|$666.
00|
|D|
用于数字类型|一般的整数|666|
|E|
数字类型|科学计数法|6.66
0000E+002|
|F|
数字类型|小数点后的位数固定|666.00
|
|G|
数字类型|一般的数字|666
|
|N|
数字类型|通常是特定地区的数字格式|666.00|
|P|
数字类型|百分比计数法|66,6
00.00%|
|X|
只用于整数类型|十六进制格式|29A|
以下程序中,能让str1等于666.0的是:
以下程序中,能让str1等于666.0的是:
##
答案
##
答案
```
csharp
string
str1
=
string
.
Format
(
"{0:F1}"
,
666
);
```
##
选项
##
选项
### A
...
...
data/1..NET初阶/3.C#特性/1.C#3.0特性/AnonymousType.md
浏览文件 @
f92f0c16
# C# 3.0
特性 匿名类型
# C# 3.0
特性 匿名类型
匿名类型提供了一种方便的方法,可以将一组只读属性封装到单个对象中,而无需先显式定义类型。类型名称由编译器生成,在源代码级别不可用。每个属性的类型由编译器推断。
您可以通过将new运算符与对象初始值设定项一起使用来创建匿名类型。
匿名类型提供了一种方便的方法,可以将一组只读属性封装到单个对象中,而无需先显式定义类型。类型名称由编译器生成,在源代码级别不可用。每个属性的类型由编译器推断。
您可以通过将new运算符与对象初始值设定项一起使用来创建匿名类型。
```
csharp
var
user
=
new
{
name
=
"Gao"
,
id
=
996
,
height
=
172.5
};
//
此时编译器会提示匿名类型, 是
new {string name, int id, double height}
var
user
=
new
{
name
=
"Gao"
,
id
=
996
,
height
=
172.5
};
//
此时编译器会提示匿名类型, 是 new {
string name, int id, double height}
Console
.
WriteLine
(
string
.
Format
(
"name {0}, id {1}, height {2}"
,
user
.
name
,
user
.
id
,
user
.
height
));
```
如果一个类里面的属性和字段太多,想要用LINQ语句查找,可以试试匿名类型。以下代码举个例子,假如有一个examples是example类的集合,然后输出所有的Name,如果直接查询会把example类的所有属性和字段带过来,使用匿名类型会导致查询中返回的数据量较少。
如果一个类里面的属性和字段太多,想要用LINQ语句查找,可以试试匿名类型。以下代码举个例子,假如有一个examples是example类的集合,然后输出所有的Name,如果直接查询会把example类的所有属性和字段带过来,使用匿名类型会导致查询中返回的数据量较少。
```
csharp
var
result
=
from
example
in
examples
select
new
{
example
.
Name
};
...
...
@@ -19,15 +19,15 @@ foreach (var item in result)
}
```
在下列选项中,可以设置一个name是“csdn”的匿名类型的是:
在下列选项中,可以设置一个name是“csdn”的匿名类型的是:
##
答案
##
答案
```
csharp
var
csdn
=
new
{
name
=
"csdn"
};
```
##
选项
##
选项
### A
...
...
data/1..NET初阶/3.C#特性/1.C#3.0特性/AutoImplementedProperties.md
浏览文件 @
f92f0c16
# C# 3.0
特性 自动实现属性
# C# 3.0
特性 自动实现属性
在 C# 3.0 及更高版本,当属性访问器中不需要任何其他逻辑时,自动实现的属性会使属性声明更加简洁。
在 C# 3.0 及更高版本,当属性访问器中不需要任何其他逻辑时,自动实现的属性会使属性声明更加简洁。
对于字段可以用属性来封装,上面代码的name就是用Name封装,并且使用时使用Name。C# 3.0特性支持了自动实现属性的访问器,这样就可以写成Id这样,也能实现一样的功能。这里的属性将set访问器声明为私有,那就是私有的访问级别,如果访问器只声明get访问器时,除了能在构造函数中可变,在其他任何位置都不可变。
对于字段可以用属性来封装,上面代码的name就是用Name封装,并且使用时使用Name。C# 3.0特性支持了自动实现属性的访问器,这样就可以写成Id这样,也能实现一样的功能。这里的属性将set访问器声明为私有,那就是私有的访问级别,如果访问器只声明get访问器时,除了能在构造函数中可变,在其他任何位置都不可变。
```
csharp
public
class
Example
...
...
@@ -24,15 +24,15 @@ public class Example
}
```
如上代码,在下列选项中,不可以设置属性值的是:
如上代码,在下列选项中,不可以设置属性值的是:
##
答案
##
答案
```
csharp
Example
example
=
new
Example
(){
UserId
=
Guid
.
NewGuid
().
ToString
()};
```
##
选项
##
选项
### A
...
...
data/1..NET初阶/3.C#特性/1.C#3.0特性/ExpressionTree.md
浏览文件 @
f92f0c16
# C# 3.0
特性 表达式树
# C# 3.0
特性 表达式树
表达式树是定义代码的数据结构。 它们基于编译器用于分析代码和生成已编译输出的相同结构。
以下代码创建了一个表达式并且执行了,Compile方法可以编译表达式树由描述为可执行代码的 lambda 表达式,并生成一个委托,表示 lambda 表达式。
注意这里不能使用var来声明此表达式树,因为此操作无法执行,这是由于赋值右侧是隐式类型而导致的。
表达式树是定义代码的数据结构。 它们基于编译器用于分析代码和生成已编译输出的相同结构。
以下代码创建了一个表达式并且执行了,Compile方法可以编译表达式树由描述为可执行代码的 lambda 表达式,并生成一个委托,表示 lambda 表达式。
注意这里不能使用var来声明此表达式树,因为此操作无法执行,这是由于赋值右侧是隐式类型而导致的。
```
csharp
Expression
<
Func
<
int
>>
add
=
()
=>
1
+
2
;
var
func
=
add
.
Compile
();
//
创建一个
delegate
var
answer
=
func
();
//
调用 delegate, 得到值3
var
func
=
add
.
Compile
();
//
创建一个
delegate
var
answer
=
func
();
//
调用 delegate, 得到值3
Console
.
WriteLine
(
answer
);
```
根据上面例子,下列选项中,可以生成一个1+2的表达式的是:
根据上面例子,下列选项中,可以生成一个1+2的表达式的是:
##
答案
##
答案
```
csharp
var
one
=
Expression
.
Constant
(
1
,
typeof
(
int
));
...
...
@@ -21,7 +21,7 @@ var two = Expression.Constant(2, typeof(int));
var
addition
=
Expression
.
Add
(
one
,
two
);
```
##
选项
##
选项
### A
...
...
data/1..NET初阶/3.C#特性/1.C#3.0特性/ExtensionMethod.md
浏览文件 @
f92f0c16
# C# 3.0
特性 扩展方法
# C# 3.0
特性 扩展方法
扩展方法使你能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。
扩展方法是一种静态方法,但可以像扩展类型上的实例方法一样进行调用。调用扩展方法与调用在类型中定义的方法没有明显区别。
扩展方法使你能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。
扩展方法是一种静态方法,但可以像扩展类型上的实例方法一样进行调用。调用扩展方法与调用在类型中定义的方法没有明显区别。
在下列选项中,是扩展方法并实现了判断字符串中是否包含Q或q的代码的是:
在下列选项中,是扩展方法并实现了判断字符串中是否包含Q或q的代码的是:
##
答案
##
答案
```
csharp
public
static
class
Extensions
...
...
@@ -25,7 +25,7 @@ public static class Extensions
}
```
##
选项
##
选项
### A
...
...
data/1..NET初阶/3.C#特性/1.C#3.0特性/LambdaExpression.md
浏览文件 @
f92f0c16
# C# 3.0
特性 Lambda 表达式
# C# 3.0
特性 Lambda 表达式
Lambda
表达式可采用表达式为其主体,也可以采用语句块作为其主体:
Lambda
表达式可采用表达式为其主体,也可以采用语句块作为其主体:
```
csharp
(
input
-
parameters
)
=>
expression
(
input
-
parameters
)
=>
{
<
sequence
-
of
-
statements
>
}
```
Lambda
表达式可以没有参数,如果有参数需要在左侧添加,任何 Lambda 表达式都可以转换为委托类型。
Lambda
表达式可以没有参数,如果有参数需要在左侧添加,任何 Lambda 表达式都可以转换为委托类型。
在下列选项中,没有编译错误并且可以输出5的平方的是:
在下列选项中,没有编译错误并且可以输出5的平方的是:
##
答案
##
答案
```
csharp
Func
<
int
,
int
>
square
=
x
=>
x
*
x
;
Console
.
WriteLine
(
square
(
5
));
```
##
选项
##
选项
### A
...
...
data/1..NET初阶/3.C#特性/1.C#3.0特性/QueryExpression.md
浏览文件 @
f92f0c16
# C# 3.0
特性 查询表达式
# C# 3.0
特性 查询表达式
查询表达式必须以from子句开头。 它指定数据源以及范围变量。查询表达式以select或group结尾。
查询表达式必须以from子句开头。 它指定数据源以及范围变量。查询表达式以select或group结尾。
*
使用 where 子句可基于一个或多个谓词表达式,从源数据中筛选出元素。
*
使用 select 子句可生成所有其他类型的序列。
*
使用 group 子句可生成按指定键组织的组的序列。
*
使用 into 关键字可以在 select 或 group 子句中创建存储查询的临时标识符。
*
使用 orderby 子句可按升序或降序对结果进行排序。
*
使用 join 子句可基于每个元素中指定的键之间的相等比较,将一个数据源中的元素与另一个数据源中的元素进行关联和/或合并。
*
使用 let 子句可将表达式(如方法调用)的结果存储在新范围变量中。
*
使用 where 子句可基于一个或多个谓词表达式,从源数据中筛选出元素。
*
使用 select 子句可生成所有其他类型的序列。
*
使用 group 子句可生成按指定键组织的组的序列。
*
使用 into 关键字可以在 select 或 group 子句中创建存储查询的临时标识符。
*
使用 orderby 子句可按升序或降序对结果进行排序。
*
使用 join 子句可基于每个元素中指定的键之间的相等比较,将一个数据源中的元素与另一个数据源中的元素进行关联和/或合并。
*
使用 let 子句可将表达式(如方法调用)的结果存储在新范围变量中。
在下列选项中,可以将examples集合中所有Count大于10的子项目按照Count从大到小的顺序格式化显示的是:
在下列选项中,可以将examples集合中所有Count大于10的子项目按照Count从大到小的顺序格式化显示的是:
##
答案
##
答案
```
csharp
from
example
in
examples
...
...
@@ -21,7 +21,7 @@ orderby example.Count descending
select
$"
{
example
.
Name
}
\t
{
example
.
Count
}
"
;
```
##
选项
##
选项
### A
...
...
data/1..NET初阶/3.C#特性/1.C#3.0特性/config.json
浏览文件 @
f92f0c16
...
...
@@ -9,7 +9,14 @@
"扩展方法"
],
"children"
:
[],
"export"
:
[],
"export"
:
[
"AnonymousType.json"
,
"LambdaExpression.json"
,
"AutoImplementedProperties.json"
,
"ExtensionMethod.json"
,
"ExpressionTree.json"
,
"QueryExpression.json"
],
"keywords_must"
:
[],
"keywords_forbid"
:
[]
}
\ No newline at end of file
data/2..NET中阶/1.ASP.NET Core应用/4.Web API应用/WebAPI.md
浏览文件 @
f92f0c16
# Web API
应用
# Web API
应用
应用程序接口(API,Application Programming Interface)是基于编程语言构建的结构,使开发人员更容易地创建复杂的功能。它们抽象了复杂的代码,并提供一些简单的接口规则直接使用。
应用程序接口(API,Application Programming Interface)是基于编程语言构建的结构,使开发人员更容易地创建复杂的功能。它们抽象了复杂的代码,并提供一些简单的接口规则直接使用。
当我们创建一个.net Core的Web API时,可以选择带有模板的,这样就自动生成了一个简单的API,而且调试的时候也会自动生成
[
swagger
](
https://swagger.io/
"swagger"
)
打开网页可查看接口详细信息和测试。如下是ValueController的代码。
当我们创建一个.net Core的Web API时,可以选择带有模板的,这样就自动生成了一个简单的API,而且调试的时候也会自动生成
[
swagger
](
https://swagger.io/
"swagger"
)
打开网页可查看接口详细信息和测试。如下是ValueController的代码。
```
csharp
[
Route
(
"api/[controller]"
)]
//
自定义特性,调用接口时可以"https://localhost/api/Values"(这里[controller]是继承ControllerBase的类名,也可以拼接很多,比如加[action]是方法名)
[
Route
(
"api/[controller]"
)]
//
自定义特性,调用接口时可以"https://localhost/api/Values"(这里[controller]是继承ControllerBase的类名,也可以拼接很多,比如加[action]是方法名)
[
ApiController
]
public
class
ValuesController
:
ControllerBase
{
...
...
@@ -19,7 +19,7 @@ public class ValuesController : ControllerBase
}
```
此时用GET调用接口会返回
此时用GET调用接口会返回
```
json
[
"value1"
,
...
...
@@ -27,19 +27,19 @@ public class ValuesController : ControllerBase
]
```
Web API
还允许在方法中使用特性来切换请求方式和参数方式
:
Web API
还允许在方法中使用特性来切换请求方式和参数方式:
```
csharp
// GET api/<ValuesController>/5
[
HttpGet
(
"{id}"
)]
//
这里的{id}就是参数
id
[
HttpGet
(
"{id}"
)]
//
这里的{id}就是参数id
public
string
Get
(
int
id
)
{
return
(
id
*
2
).
ToString
();
}
// POST api/<ValuesController>
[
HttpPost
]
//
这里用了POST方法
public
void
Post
([
FromBody
]
string
value
)
//FromBody
特性,
curl -X POST "https://localhost/api/Values" -H "accept: */*" -H "Content-Type: application/json" -d "\"string\""
[
HttpPost
]
//
这里用了POST方法
public
void
Post
([
FromBody
]
string
value
)
//FromBody
特性,c
url -X POST "https://localhost/api/Values" -H "accept: */*" -H "Content-Type: application/json" -d "\"string\""
{
}
...
...
@@ -102,16 +102,16 @@ public class TestController : ControllerBase
}
```
如上代码,在下列选项中,可以正确获取Test接口的是:
如上代码,在下列选项中,可以正确获取Test接口的是:
##
答案
##
答案
```
curl -X GET "https://localhost:44326/api/Test/Sum?num1=6&num2=6" -H "accept: text/plain"
curl -X GET "https://localhost:44326/api/Test/Copy/str" -H "accept: text/plain"
```
##
选项
##
选项
### A
...
...
data/2..NET中阶/1.ASP.NET Core应用/4.Web API应用/config.json
浏览文件 @
f92f0c16
...
...
@@ -4,7 +4,9 @@
".NET Web API"
],
"children"
:
[],
"export"
:
[],
"export"
:
[
"WebAPI.json"
],
"keywords_must"
:
[],
"keywords_forbid"
:
[]
}
\ No newline at end of file
main.py
浏览文件 @
f92f0c16
# -*- coding: utf-8 -*-
from
s
rc
.tree
import
TreeWalker
from
s
kill_tree
.tree
import
TreeWalker
if
__name__
==
'__main__'
:
walker
=
TreeWalker
(
"data"
,
"csharp"
,
"csharp"
)
...
...
requirement.txt
浏览文件 @
f92f0c16
uuid==1.30
\ No newline at end of file
skill-tree-parser~=0.0.5
\ No newline at end of file
src/tree.py
已删除
100644 → 0
浏览文件 @
b7ce0d39
import
json
import
logging
import
os
import
re
import
subprocess
import
sys
import
uuid
import
re
id_set
=
set
()
logger
=
logging
.
getLogger
(
__name__
)
logger
.
setLevel
(
logging
.
INFO
)
handler
=
logging
.
StreamHandler
(
sys
.
stdout
)
formatter
=
logging
.
Formatter
(
'%(asctime)s - %(levelname)s - %(message)s'
)
handler
.
setFormatter
(
formatter
)
logger
.
addHandler
(
handler
)
def
search_author
(
author_dict
,
username
):
for
key
in
author_dict
:
names
=
author_dict
[
key
]
if
username
in
names
:
return
key
return
username
def
user_name
(
md_file
,
author_dict
):
ret
=
subprocess
.
Popen
([
"git"
,
"log"
,
md_file
],
stdout
=
subprocess
.
PIPE
)
lines
=
list
(
map
(
lambda
l
:
l
.
decode
(),
ret
.
stdout
.
readlines
()))
author_lines
=
[]
for
line
in
lines
:
if
line
.
startswith
(
'Author'
):
author_lines
.
append
(
line
.
split
(
' '
)[
1
])
author_nick_name
=
author_lines
[
-
1
]
return
search_author
(
author_dict
,
author_nick_name
)
def
load_json
(
p
):
with
open
(
p
,
'r'
,
encoding
=
"utf-8"
)
as
f
:
return
json
.
loads
(
f
.
read
())
def
dump_json
(
p
,
j
,
exist_ok
=
False
,
override
=
False
):
if
os
.
path
.
exists
(
p
):
if
exist_ok
:
if
not
override
:
return
else
:
logger
.
error
(
f
"
{
p
}
already exist"
)
sys
.
exit
(
0
)
with
open
(
p
,
'w+'
,
encoding
=
"utf8"
)
as
f
:
f
.
write
(
json
.
dumps
(
j
,
indent
=
2
,
ensure_ascii
=
False
))
def
ensure_config
(
path
):
config_path
=
os
.
path
.
join
(
path
,
"config.json"
)
if
not
os
.
path
.
exists
(
config_path
):
node
=
{
"keywords"
:
[]}
dump_json
(
config_path
,
node
,
exist_ok
=
True
,
override
=
False
)
return
node
else
:
return
load_json
(
config_path
)
def
parse_no_name
(
d
):
p
=
r
'(\d+)\.(.*)'
m
=
re
.
search
(
p
,
d
)
try
:
no
=
int
(
m
.
group
(
1
))
dir_name
=
m
.
group
(
2
)
except
:
sys
.
exit
(
0
)
return
no
,
dir_name
def
check_export
(
base
,
cfg
):
flag
=
False
exports
=
[]
for
export
in
cfg
.
get
(
'export'
,
[]):
ecfg_path
=
os
.
path
.
join
(
base
,
export
)
if
os
.
path
.
exists
(
ecfg_path
):
exports
.
append
(
export
)
else
:
flag
=
True
if
flag
:
cfg
[
"export"
]
=
exports
return
flag
class
TreeWalker
:
def
__init__
(
self
,
root
,
tree_name
,
title
=
None
,
log
=
None
,
authors
=
None
,
enable_notebook
=
None
,
ignore_keywords
=
False
):
self
.
ignore_keywords
=
ignore_keywords
self
.
authors
=
authors
if
authors
else
{}
self
.
enable_notebook
=
enable_notebook
self
.
name
=
tree_name
self
.
root
=
root
self
.
title
=
tree_name
if
title
is
None
else
title
self
.
tree
=
{}
self
.
logger
=
logger
if
log
is
None
else
log
def
walk
(
self
):
root
=
self
.
load_root
()
root_node
=
{
"node_id"
:
root
[
"node_id"
],
"keywords"
:
root
[
"keywords"
],
"children"
:
[],
"keywords_must"
:
root
[
"keywords_must"
],
"keywords_forbid"
:
root
[
"keywords_forbid"
]
}
self
.
tree
[
root
[
"tree_name"
]]
=
root_node
self
.
load_levels
(
root_node
)
self
.
load_chapters
(
self
.
root
,
root_node
)
for
index
,
level
in
enumerate
(
root_node
[
"children"
]):
level_title
=
list
(
level
.
keys
())[
0
]
level_node
=
list
(
level
.
values
())[
0
]
level_path
=
os
.
path
.
join
(
self
.
root
,
f
"
{
index
+
1
}
.
{
level_title
}
"
)
self
.
load_chapters
(
level_path
,
level_node
)
for
index
,
chapter
in
enumerate
(
level_node
[
"children"
]):
chapter_title
=
list
(
chapter
.
keys
())[
0
]
chapter_node
=
list
(
chapter
.
values
())[
0
]
chapter_path
=
os
.
path
.
join
(
level_path
,
f
"
{
index
+
1
}
.
{
chapter_title
}
"
)
self
.
load_sections
(
chapter_path
,
chapter_node
)
for
index
,
section_node
in
enumerate
(
chapter_node
[
"children"
]):
section_title
=
list
(
section_node
.
keys
())[
0
]
full_path
=
os
.
path
.
join
(
chapter_path
,
f
"
{
index
+
1
}
.
{
section_title
}
"
)
if
os
.
path
.
isdir
(
full_path
):
self
.
check_section_keywords
(
full_path
)
self
.
ensure_exercises
(
full_path
)
tree_path
=
os
.
path
.
join
(
self
.
root
,
"tree.json"
)
dump_json
(
tree_path
,
self
.
tree
,
exist_ok
=
True
,
override
=
True
)
return
self
.
tree
def
sort_dir_list
(
self
,
dirs
):
result
=
[
self
.
extract_node_env
(
dir
)
for
dir
in
dirs
]
result
.
sort
(
key
=
lambda
item
:
item
[
0
])
return
result
def
load_levels
(
self
,
root_node
):
levels
=
[]
for
level
in
os
.
listdir
(
self
.
root
):
if
not
os
.
path
.
isdir
(
level
):
continue
level_path
=
os
.
path
.
join
(
self
.
root
,
level
)
num
,
config
=
self
.
load_level_node
(
level_path
)
levels
.
append
((
num
,
config
))
levels
=
self
.
resort_children
(
self
.
root
,
levels
)
root_node
[
"children"
]
=
[
item
[
1
]
for
item
in
levels
]
return
root_node
def
load_level_node
(
self
,
level_path
):
config
=
self
.
ensure_level_config
(
level_path
)
num
,
name
=
self
.
extract_node_env
(
level_path
)
result
=
{
name
:
{
"node_id"
:
config
[
"node_id"
],
"keywords"
:
config
[
"keywords"
],
"children"
:
[],
"keywords_must"
:
config
[
"keywords_must"
],
"keywords_forbid"
:
config
[
"keywords_forbid"
]
}
}
return
num
,
result
def
load_chapters
(
self
,
base
,
level_node
):
chapters
=
[]
for
name
in
os
.
listdir
(
base
):
full_name
=
os
.
path
.
join
(
base
,
name
)
if
os
.
path
.
isdir
(
full_name
):
num
,
chapter
=
self
.
load_chapter_node
(
full_name
)
chapters
.
append
((
num
,
chapter
))
chapters
=
self
.
resort_children
(
base
,
chapters
)
level_node
[
"children"
]
=
[
item
[
1
]
for
item
in
chapters
]
return
level_node
def
load_sections
(
self
,
base
,
chapter_node
):
sections
=
[]
for
name
in
os
.
listdir
(
base
):
full_name
=
os
.
path
.
join
(
base
,
name
)
if
os
.
path
.
isdir
(
full_name
):
num
,
section
=
self
.
load_section_node
(
full_name
)
sections
.
append
((
num
,
section
))
sections
=
self
.
resort_children
(
base
,
sections
)
chapter_node
[
"children"
]
=
[
item
[
1
]
for
item
in
sections
]
return
chapter_node
def
resort_children
(
self
,
base
,
children
):
children
.
sort
(
key
=
lambda
item
:
item
[
0
])
for
index
,
[
number
,
element
]
in
enumerate
(
children
):
title
=
list
(
element
.
keys
())[
0
]
origin
=
os
.
path
.
join
(
base
,
f
"
{
number
}
.
{
title
}
"
)
posted
=
os
.
path
.
join
(
base
,
f
"
{
index
+
1
}
.
{
title
}
"
)
if
origin
!=
posted
:
self
.
logger
.
info
(
f
"rename [
{
origin
}
] to [
{
posted
}
]"
)
os
.
rename
(
origin
,
posted
)
return
children
def
ensure_chapters
(
self
):
for
subdir
in
os
.
listdir
(
self
.
root
):
self
.
ensure_level_config
(
subdir
)
def
load_root
(
self
):
config_path
=
os
.
path
.
join
(
self
.
root
,
"config.json"
)
if
not
os
.
path
.
exists
(
config_path
):
config
=
{
"tree_name"
:
self
.
name
,
"keywords"
:
[],
"node_id"
:
self
.
gen_node_id
(),
"keywords_must"
:
[],
"keywords_forbid"
:
[]
}
dump_json
(
config_path
,
config
,
exist_ok
=
True
,
override
=
True
)
else
:
config
=
load_json
(
config_path
)
flag
,
result
=
self
.
ensure_node_id
(
config
)
if
flag
:
dump_json
(
config_path
,
result
,
exist_ok
=
True
,
override
=
True
)
return
config
def
ensure_level_config
(
self
,
path
):
config_path
=
os
.
path
.
join
(
path
,
"config.json"
)
if
not
os
.
path
.
exists
(
config_path
):
config
=
{
"node_id"
:
self
.
gen_node_id
()
}
dump_json
(
config_path
,
config
,
exist_ok
=
True
,
override
=
True
)
else
:
config
=
load_json
(
config_path
)
flag
,
result
=
self
.
ensure_node_id
(
config
)
if
flag
:
dump_json
(
config_path
,
config
,
exist_ok
=
True
,
override
=
True
)
return
config
def
ensure_chapter_config
(
self
,
path
):
config_path
=
os
.
path
.
join
(
path
,
"config.json"
)
if
not
os
.
path
.
exists
(
config_path
):
config
=
{
"node_id"
:
self
.
gen_node_id
(),
"keywords"
:
[],
"keywords_must"
:
[],
"keywords_forbid"
:
[]
}
dump_json
(
config_path
,
config
,
exist_ok
=
True
,
override
=
True
)
else
:
config
=
load_json
(
config_path
)
flag
,
result
=
self
.
ensure_node_id
(
config
)
if
flag
:
dump_json
(
config_path
,
config
,
exist_ok
=
True
,
override
=
True
)
return
config
def
ensure_section_config
(
self
,
path
):
config_path
=
os
.
path
.
join
(
path
,
"config.json"
)
if
not
os
.
path
.
exists
(
config_path
):
config
=
{
"node_id"
:
self
.
gen_node_id
(),
"keywords"
:
[],
"children"
:
[],
"export"
:
[]
}
dump_json
(
config_path
,
config
,
exist_ok
=
True
,
override
=
True
)
else
:
config
=
load_json
(
config_path
)
flag
,
result
=
self
.
ensure_node_id
(
config
)
if
flag
:
dump_json
(
config_path
,
result
,
exist_ok
=
True
,
override
=
True
)
return
config
def
ensure_node_id
(
self
,
config
):
flag
=
False
if
"node_id"
not
in
config
or
\
not
config
[
"node_id"
].
startswith
(
f
"
{
self
.
name
}
-"
)
or
\
config
[
"node_id"
]
in
id_set
:
new_id
=
self
.
gen_node_id
()
id_set
.
add
(
new_id
)
config
[
"node_id"
]
=
new_id
flag
=
True
for
child
in
config
.
get
(
"children"
,
[]):
child_node
=
list
(
child
.
values
())[
0
]
f
,
_
=
self
.
ensure_node_id
(
child_node
)
flag
=
flag
or
f
return
flag
,
config
def
gen_node_id
(
self
):
return
f
"
{
self
.
name
}
-
{
uuid
.
uuid4
().
hex
}
"
def
extract_node_env
(
self
,
path
):
try
:
_
,
dir
=
os
.
path
.
split
(
path
)
self
.
logger
.
info
(
path
)
number
,
title
=
dir
.
split
(
"."
,
1
)
return
int
(
number
),
title
except
Exception
as
error
:
self
.
logger
.
error
(
f
"目录 [
{
path
}
] 解析失败,结构不合法,可能是缺少序号"
)
# sys.exit(1)
raise
error
def
load_chapter_node
(
self
,
full_name
):
config
=
self
.
ensure_chapter_config
(
full_name
)
num
,
name
=
self
.
extract_node_env
(
full_name
)
result
=
{
name
:
{
"node_id"
:
config
[
"node_id"
],
"keywords"
:
config
[
"keywords"
],
"children"
:
[],
"keywords_must"
:
config
[
"keywords_must"
],
"keywords_forbid"
:
config
[
"keywords_forbid"
]
}
}
return
num
,
result
def
load_section_node
(
self
,
full_name
):
config
=
self
.
ensure_section_config
(
full_name
)
num
,
name
=
self
.
extract_node_env
(
full_name
)
result
=
{
name
:
{
"node_id"
:
config
[
"node_id"
],
"keywords"
:
config
[
"keywords"
],
"children"
:
config
.
get
(
"children"
,
[]),
"keywords_must"
:
config
[
"keywords_must"
],
"keywords_forbid"
:
config
[
"keywords_forbid"
]
}
}
# if "children" in config:
# result["children"] = config["children"]
return
num
,
result
def
ensure_exercises
(
self
,
section_path
):
config
=
self
.
ensure_section_config
(
section_path
)
flag
=
False
for
e
in
os
.
listdir
(
section_path
):
base
,
ext
=
os
.
path
.
splitext
(
e
)
_
,
source
=
os
.
path
.
split
(
e
)
if
ext
!=
".md"
:
continue
mfile
=
base
+
".json"
meta_path
=
os
.
path
.
join
(
section_path
,
mfile
)
md_file
=
os
.
path
.
join
(
section_path
,
e
)
self
.
ensure_exercises_meta
(
meta_path
,
source
,
md_file
)
export
=
config
.
get
(
"export"
,
[])
if
mfile
not
in
export
and
self
.
name
!=
"algorithm"
:
export
.
append
(
mfile
)
flag
=
True
config
[
"export"
]
=
export
if
flag
:
dump_json
(
os
.
path
.
join
(
section_path
,
"config.json"
),
config
,
True
,
True
)
for
e
in
config
.
get
(
"export"
,
[]):
full_name
=
os
.
path
.
join
(
section_path
,
e
)
exercise
=
load_json
(
full_name
)
if
"exercise_id"
not
in
exercise
or
exercise
.
get
(
"exercise_id"
)
in
id_set
:
eid
=
uuid
.
uuid4
().
hex
exercise
[
"exercise_id"
]
=
eid
dump_json
(
full_name
,
exercise
,
True
,
True
)
else
:
id_set
.
add
(
exercise
[
"exercise_id"
])
def
ensure_exercises_meta
(
self
,
meta_path
,
source
,
md_file
):
_
,
mfile
=
os
.
path
.
split
(
meta_path
)
meta
=
None
if
os
.
path
.
exists
(
meta_path
):
with
open
(
meta_path
)
as
f
:
content
=
f
.
read
()
if
content
:
meta
=
json
.
loads
(
content
)
if
"exercise_id"
not
in
meta
:
meta
[
"exercise_id"
]
=
uuid
.
uuid4
().
hex
if
"notebook_enable"
not
in
meta
:
meta
[
"notebook_enable"
]
=
self
.
default_notebook
()
if
"source"
not
in
meta
:
meta
[
"source"
]
=
source
if
"author"
not
in
meta
:
meta
[
"author"
]
=
user_name
(
md_file
,
self
.
authors
)
if
"type"
not
in
meta
:
meta
[
"type"
]
=
"code_options"
if
meta
is
None
:
meta
=
{
"type"
:
"code_options"
,
"author"
:
user_name
(
md_file
,
self
.
authors
),
"source"
:
source
,
"notebook_enable"
:
self
.
default_notebook
(),
"exercise_id"
:
uuid
.
uuid4
().
hex
}
dump_json
(
meta_path
,
meta
,
True
,
True
)
def
default_notebook
(
self
):
if
self
.
enable_notebook
is
not
None
:
return
self
.
enable_notebook
if
self
.
name
in
[
"python"
,
"java"
,
"c"
]:
return
True
else
:
return
False
def
check_section_keywords
(
self
,
full_path
):
if
self
.
ignore_keywords
:
return
config
=
self
.
ensure_section_config
(
full_path
)
if
not
config
.
get
(
"keywords"
,
[]):
self
.
logger
.
error
(
f
"节点 [
{
full_path
}
] 的关键字为空,请修改配置文件写入关键字"
)
sys
.
exit
(
1
)
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录