种草计划

饲草种植

土地

承包土地500元一亩,前期10亩,中期50亩,后期100亩
租金500元一亩,成本如下

10亩 50亩 100亩
0元 2.5万 5万

耕种

采用冬小麦和牧草轮种的方式

冬小麦 牧草
播种时间 10月30-11月5号 6月5号-6月10号
收获时间 5月30-6月5号 10月15号

信源
https://www.sohu.com/a/498785948_121123752
https://hn.cnr.cn/hnpdgb/hngexb/20221031/t20221031_526046737.html

种植品种

巨菌草

采用种节种植,首年10亩规模种节购买于菌草中心海南基地,每亩成本400元,总成本4000,第二年采用自留种节过冬,温室大棚育种的方式,降低成本,成本可大幅降低甚至忽略不计
产量
根据福建农林大学的实验论文
大约15吨每亩
2023-08-28-14-50-08-QGFjTk-fRwsIj
2023-08-28-14-48-37-Vh04h4-ZCEQ9Z

售价大约500元一吨
2023-08-28-15-23-40-rAIioc-dRE2Nc
2023-08-28-15-24-38-uJTCWS-nmJVUo
2023-08-28-15-24-57-xovK3H-BqWXSZ

巨型甜高粱

直接购买种子播种即可

青贮玉米

亦可尝试

收割

采用机械化的方式收割,粉碎,采用机械包膜和青储窖结合的方式存放
2023-08-28-16-00-44-wjINQ3-BIbalG

| 收割机 | 包膜机 | 铲车| 青储窖施工|总计|
| —- | —- |—- |—- |—- |—- |
| 15万 | 3万 | 5万 | 2万| 20万 |

总结:

首年投资

| 固定资产和设备 | 土地 | 其他|总计|
| —- | —- |—- |—- |—- |
| 20万 | 0万 | 5万 | 25万 |

首年收益

| 产量 | 单价 | 耗材成本|总计|
| —- | —- |—- |—- |—- |
| 150吨 | 400元/吨 |0.75万 | 6.7万 |

首年亏18.3

次年投资和收益

| 固定资产和设备 | 土地|其他| 总计|
| —- |—- |—- |—-|—- |
| 0 | 2.5万 | 2万 | 4.5万|

次年收益

| 产量 | 单价 | 耗材成本|总计|
| —- | —- |—- |—- |—- |
| 750吨 | 400元/吨 |3.75万 | 26.3万 |

盈利21.8

第三年投资和收益

| 固定资产和设备 | 土地 | 其他|总计|
| —- | —- |—- |—- |—- |
| 0 | 5万 | 4万 | 9万 |

第三年收益

| 产量 | 单价 | 耗材成本|总计|
| —- | —- |—- |—- |—- |
| 1500吨 | 400元/吨 |7.5万 | 52.5万 |

盈利43.5

三棵树

widget翻译

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Describes the configuration for an [Element].

Widgets are the central class hierarchy in the Flutter framework. A widget
is an immutable description of part of a user interface. Widgets can be
inflated into elements, which manage the underlying render tree.

Widgets themselves have no mutable state (all their fields must be final).
If you wish to associate mutable state with a widget, consider using a
[StatefulWidget], which creates a [State] object (via
[StatefulWidget.createState]) whenever it is inflated into an element and
incorporated into the tree.

A given widget can be included in the tree zero or more times. In particular
a given widget can be placed in the tree multiple times. Each time a widget
is placed in the tree, it is inflated into an [Element], which means a
widget that is incorporated into the tree multiple times will be inflated
multiple times.

The [key] property controls how one widget replaces another widget in the
tree. If the [runtimeType] and [key] properties of the two widgets are
[operator==], respectively, then the new widget replaces the old widget by
updating the underlying element (i.e., by calling [Element.update] with the
new widget). Otherwise, the old element is removed from the tree, the new
widget is inflated into an element, and the new element is inserted into the
tree.

See also:

* [StatefulWidget] and [State], for widgets that can build differently
several times over their lifetime.
* [InheritedWidget], for widgets that introduce ambient state that can
be read by descendant widgets.
* [StatelessWidget], for widgets that always build the same way given a
particular configuration and ambient state.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
好的,我已经翻译了您的英文段落。请看下面的汉语版本。😊

Okay, I have translated your English paragraph. Please see the Chinese version below. 😊

/// 描述了[Element]的配置。
///
/// Widgets是Flutter框架中的核心类层次结构。一个widget是用户界面部分的不可变描述。Widgets可以被扩展成elements,它们管理底层的渲染树。
///
/// Widgets本身没有可变状态(它们的所有字段都必须是final)。如果您想要将可变状态与widget关联起来,请考虑使用[StatefulWidget],它在每次被扩展成element并加入到树中时,都会创建一个[State]对象(通过[StatefulWidget.createState])。
///
/// 一个给定的widget可以被包含在树中零次或多次。特别地,一个给定的widget可以被放置在树中多次。每次一个widget被放置在树中时,它都会被扩展成一个[Element],这意味着一个被加入到树中多次的widget将会被扩展多次。
///
/// [key]属性控制了一个widget如何替换树中的另一个widget。如果两个widget的[runtimeType]和[key]属性分别是[operator==],那么新的widget就会通过更新底层的element(即通过调用[Element.update]并传入新的widget)来替换旧的widget。否则,旧的element就会从树中移除,新的widget就会被扩展成一个element,并且新的element就会插入到树中。
///
/// 另请参阅:
///
/// * [StatefulWidget]和[State],用于可以在其生命周期内以不同方式构建多次的widgets。
/// * [InheritedWidget],用于引入可以被后代widgets读取的环境状态。
/// * [StatelessWidget],用于始终以相同方式构建(给定特定配置和环境状态)的widgets。

Source: Conversation with Bing, 2/27/2023(1) . https://bing.com/search?q=translate+to+Chinese Accessed 2/27/2023.
(2) Google Translate. https://translate.google.com/;) Accessed 2/27/2023.
(3) Google 翻譯. https://translate.google.com/?hl=zh-TW Accessed 2/27/2023.
(4) DeepL Translate: The world's most accurate translator. https://www.deepl.com/en/translator-mobile Accessed 2/27/2023.

代码片段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
String uri = "http://10.12.29.138:8080/IMG_5899.png";
String extension = uri.substring(uri.lastIndexOf(".") + 1);
File savedFile = new File("/Users/admin/Downloads/123." + extension);
FileUtils.copyURLToFile(new URL(uri), savedFile);

Metadata metadata = ImageMetadataReader.readMetadata(savedFile);
// See whether it has GPS data
Collection<GpsDirectory> gpsDirectories = metadata.getDirectoriesOfType(GpsDirectory.class);
for (GpsDirectory gpsDirectory : gpsDirectories) {
// Try to read out the location, making sure it's non-zero
GeoLocation geoLocation = gpsDirectory.getGeoLocation();
if (geoLocation != null && !geoLocation.isZero()) {
System.out.println(geoLocation.getLatitude());
System.out.println(geoLocation.getLongitude());
}
}
}

Centos 7 docker ftp

拉取镜像

1
2
3
4
docker pull nginx

docker pull vsftpd

docker启动nginx容器,命名为test

nginx配置default.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
cat default.conf
server {
listen 80;
listen [::]:80;
server_name localhost;

#access_log /var/log/nginx/host.access.log main;

location / {
root /mnt/data;
index index.html index.htm;
}

#error_page 404 /404.html;

# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}

# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}

# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}

# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}

nginx配置nginx.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
cat nginx.conf

user root;
worker_processes auto;

error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;


events {
worker_connections 1024;
}


http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main;

sendfile on;
#tcp_nopush on;

keepalive_timeout 65;

#gzip on;

include /etc/nginx/conf.d/*.conf;
}

docker启动nginx

1
2
3
4
5
6
7
8
9
docker run -d -p 80:80 \
--name nginx --net host \
-v /usr/docker/nginx/nginx.conf:/etc/nginx/nginx.conf \
-v /usr/docker/nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf \
-v /usr/docker/nginx/html:/usr/share/nginx/html \
-v /usr/docker/vsftpd:/mnt/data \
-v /usr/docker/nginx/logs:/var/log/nginx \
--privileged=true --restart=always nginx

docker启动vsftpd

1
2
3
4
5
6
7
docker run -d -v /root/docker/vsftpd:/home/vsftpd \
-p 20:20 -p 21:21 -p 21100-21110:21100-21110 \
-e FTP_USER=test -e FTP_PASS=testgs \
-e PASV_ADDRESS=104.225.145.216 \
-e PASV_MIN_PORT=21100 -e PASV_MAX_PORT=21110 \
--name vsftpd --restart=always fauria/vsftpd

秘诀在于 ftp的被映射出来的文件路径 /root/dockers/vsftpd:/home/vsftpd
刚好和nginx的 root /mnt/data映射出来的路径一致
访问nginx的root,就相当于访问了ftp的文件目录

Hello World

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

tags

1
2
tags: [life,travel]  

1
2
3
4
tags:
- jQuery
- 表格
- 表单验证

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

docker笔记

centos安装docker
https://docs.docker.com/engine/install/centos/

重启之后记得启动docker

sudo systemctl start docker

查看docker是否在运行
docker version
或者
docker info

查看存在的镜像
docker image ls

删除镜像
docker image rm [imageName]

Verify that Docker Engine is installed correctly by running the hello-world image.

docker run hello-world
docker image ls

docker container kill [containID]

本机正在运行的容器
docker container ls

所有容器,包括终止的
docker container ls –all

终止运行的容器文件,依然会占据硬盘空间,可以使用docker container rm命令删除。

docker container rm [containerID]

启动已经生成、已经停止运行的容器,而不是新建一个容器
docker container start

docker run -d –name johntomcat -d -p 8081:8080 -v /root/tomcatFiles/conf/:/usr/local/tomcat/conf/ -v /root/tomcatFiles/webapps/:/usr/local/tomcat/webapps/ -v /root/tomcatFiles/logs/:/usr/local/tomcat/logs/ tomcat:8.5.56

206 docker container ls –all
207 docker container stop 50c6c266d679
208 docker container start 50c6c266d679

docker container ls –all
docker container rm 50c6c266d679

docker container ls --all

从宿主机拷文件到容器里面:
宿主机执行命令: docker cp 要拷贝的文件路径 容器id:要拷贝到容器里面对应的路径

docker安装mysql:5.7

415 docker pull mysql:5.7
416 docker image ls
417 docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=替换成自己的强密码 mysql:5.7 –character-set-server=utf8mb4 –collation-server=utf8mb4_unicode_ci
418 docker container ls –all
420 docker exec -it 36a9cf58f7e6 bash
status;
exit
exit

docker port bdb45647f017 查看端口映射信息
docker port container_tomcat
docker logs -f bdb45647f017

使用docker inspect查看Docker 容器的配置和状态信息

docker inspect bdb45647f017

正则表达式

1

1
2
3
4
5
//快捷打印
public static void print(Object o){
System.out.println(o);
}

1

1
2
3
4
5
6
\d 匹配数字 任意个数数字 

print("a8738bkj2238c0918".replaceAll("\\d","_"));

输出 a____bkj____c____

1
2
3
4
5
6
7
Pattern类的使用
Pattern pattern = Pattern.compile("\\d");
Matcher matcher = pattern.matcher("abc");
print( matcher.matches());

true

. * + ?

1
2
3
4
5
6
7
8
9
10
. 匹配任何,任何的字符

* 匹配前面的子表达式零次或多次。例如,zo*能匹配“z”以及“zoo”。*等价于{0,}。

+ 匹配前面的子表达式一次或多次。例如,“zo+”能匹配“zo”以及“zoo”,但不能匹配“z”。+等价于{1,}。

? 当该字符紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串“oooo”,“o+?”将匹配单个“o”,而“o+”将匹配所有“o”。

? 在正则表达式中元字符 ? 标记在符号前面的字符为可选,即出现 0 或 1 次。 例如,表达式 [T]?he 匹配字符串 he 和 The。

{} 号

1
2
{}  限定一个或一组字符可以重复出现的次数。 例如, 表达式 [0-9]{2,3} 匹配最少 2 位最多 3 位 0~9 的数字。

[ ]

1
[ ]	字符种类。匹配方括号内的任意字符。

范围 []

\s \w \d \

1
2
3
4
5
6
7
8
\	转义字符,用于匹配一些保留的字符 [ ] ( ) { } . * + ? ^ $ \ |

\d 匹配数字: [0-9]

\s 匹配所有空格(空白)字符,等同于: [\t\n\f\r\p{Z}]

\w 匹配所有字母数字,等同于 [a-zA-Z0-9_]

元字符

元字符 描述
. 句号匹配任意单个字符除了换行符。
[ ] 字符种类。匹配方括号内的任意字符。
[^ ] 否定的字符种类。匹配除了方括号里的任意字符
* 匹配>=0个重复的在*号之前的字符。
+ 匹配>=1个重复的+号前的字符。
? 标记?之前的字符为可选.
{n,m} 匹配num个大括号之前的字符或字符集 (n <= num <= m).
(xyz) 字符集,匹配与 xyz 完全相等的字符串.
| 或运算符,匹配符号前或后的字符.
\ 转义字符,用于匹配一些保留的字符 [ ] ( ) { } . * + ? ^ $ \ |
^ 从开始行开始匹配.
$ 从末端开始匹配.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
打印工具类
public static void P(CharSequence charSequence,String sRegex){
Pattern p = Pattern.compile(sRegex); // create the pattern only once,
Matcher m = p.matcher(charSequence);
while (m.find()) {
System.out.println( m.group() );
}
}
```

## 元字符详解 .

.是元字符中最简单的例子。 .匹配任意单个字符,但不匹配换行符。

<pre>
".ar" => The <a href="#learn-regex"><strong>car</strong></a> <a href="#learn-regex"><strong>par</strong></a>ked in the <a href="#learn-regex"><strong>gar</strong></a>age.
</pre>


```java
P("The car parked in the garage.",".ar");

输出
car
par
gar

元字符详解 [ ]

字符集也叫做字符类。
方括号用来指定一个字符集。
在方括号中使用连字符来指定字符集的范围。
在方括号中的字符集不关心顺序。
例如,表达式[Tt]he 匹配 theThe

"[Tt]he" => The car parked in the garage.
1
2
3
4
5
6
 P("The car parked in the garage.","[Tt]he");

输出
The
the

方括号的点号就表示点号。
表达式 ar[.] 匹配 ar.字符串

"ar[.]" => A garage is a good place to park a car.
1
2
3
4
5
6

P("A garage is a good place to park a car.","ar[.]");
输出
ar.


元字符详解 ^ 否定字符集

一般来说 ^ 表示一个字符串的开头,但它用在一个方括号的开头的时候,它表示这个字符集是否定的。
例如,表达式[^c]ar 匹配一个后面跟着ar的除了c的任意字符。

"[^c]ar" => The car parked in the garage.
1
2
3
4
5
6

P("The car parked in the garage.","[^c]ar");
输出
par
gar

重复次数 * + ?

后面跟着元字符 +,* or ? 的,用来指定匹配子模式的次数。

*

*号匹配 在*之前的字符出现大于等于0次。
例如,表达式 a* 匹配0或更多个以a开头的字符。表达式[a-z]* 匹配一个行中所有以小写字母开头的字符串。

"[a-z]*" => The car parked in the garage #21.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
P("The car parked in the garage Abc.","[a-z]*");
结果

he

car

parked

in

the

garage


bc


*字符和.字符搭配可以匹配所有的字符.*
*和表示匹配空格的符号\s连起来用,如表达式\s*cat\s*匹配0或更多个空格开头和0或更多个空格结尾的cat字符串。

"\s*cat\s*" => The fat cat sat on the concatenation.
1
2
3
P("The fat cat sat on the concatenation.","\\s*cat\\s*");
cat
cat

+

+号匹配+号之前的字符出现 >=1 次。
例如表达式c.+t 匹配以首字母c开头以t结尾,中间跟着至少一个字符的字符串。

"c.+t" => The fat cat sat on the mat.
1
2
P("The fat cat sat on the mat.","c.+t");
cat sat on the mat

?

在正则表达式中元字符 ? 标记在符号前面的字符为可选,即出现 0 或 1 次。
例如,表达式 [T]?he 匹配字符串 heThe

"[T]he" => The car is parked in the garage.
"[T]?he" => The car is parked in the garage.
1
2
3
4
P("The car is parked in the garage.","[T]?he");
输出
The
he

{}

在正则表达式中 {} 是一个量词,常用来限定一个或一组字符可以重复出现的次数。
例如, 表达式 [0-9]{2,3} 匹配最少 2 位最多 3 位 0~9 的数字。

"[0-9]{2,3}" => The number was 9.9997 but we rounded it off to 10.0.
1
2
3
4
P("The number was 9.9997 but we rounded it off to 10.0.","[0-9]{2,3}");
输出
999
10

我们可以省略第二个参数。
例如,[0-9]{2,} 匹配至少两位 0~9 的数字。

"[0-9]{2,}" => The number was 9.9997 but we rounded it off to 10.0.
1
2
3
4
P("The number was 9.9997 but we rounded it off to 10.0.","[0-9]{2,}");
输出
9997
10

如果逗号也省略掉则表示重复固定的次数。
例如,[0-9]{3} 匹配3位数字

"[0-9]{3}" => The number was 9.9997 but we rounded it off to 10.0.
1
2
3
4
5
P("The number was 9.9997 but we rounded it off to 10.0.","[0-9]{2}");
输出
99
97
10

(...) 特征标群

特征标群是一组写在 (...) 中的子模式。(...) 中包含的内容将会被看成一个整体,和数学中小括号( )的作用相同。例如, 表达式 (ab)* 匹配连续出现 0 或更多个 ab。如果没有使用 (...) ,那么表达式 ab* 将匹配连续出现 0 或更多个 b 。再比如之前说的 {} 是用来表示前面一个字符出现指定次数。但如果在 {} 前加上特征标群 (...) 则表示整个标群内的字符重复 N 次。

我们还可以在 () 中用或字符 | 表示或。例如,(c|g|p)ar 匹配 cargarpar.

"(c|g|p)ar" => The car is parked in the garage.
1
2
3
4
5
P("The car is parked in the garage.","(c|g|p)ar");
输出
car
par
gar

| 或运算符

或运算符就表示或,用作判断条件。

例如 (T|t)he|car 匹配 (T|t)hecar

"(T|t)he|car" => The car is parked in the garage.
1
2
3
4
5
P("The car is parked in the garage.","(T|t)he|car");
输出
The
car
the

转码特殊字符

反斜线 \ 在表达式中用于转码紧跟其后的字符。用于指定 { } [ ] / \ + * . $ ^ | ? 这些特殊字符。如果想要匹配这些特殊字符则要在其前面加上反斜线 \

例如 . 是用来匹配除换行符外的所有字符的。如果想要匹配句子中的 . 则要写成 \. 以下这个例子 \.?是选择性匹配.

"(f|c|m)at\.?" => The fat cat sat on the mat.
1
2
3
4
5
P("The fat cat sat on the mat.","(f|c|m)at\\.?");
输出
fat
cat
mat.

锚点 ^ $

在正则表达式中,想要匹配指定开头或结尾的字符串就要使用到锚点。^ 指定开头,$ 指定结尾。

^

^ 用来检查匹配的字符串是否在所匹配字符串的开头。

例如,在 abc 中使用表达式 ^a 会得到结果 a。但如果使用 ^b 将匹配不到任何结果。因为在字符串 abc 中并不是以 b 开头。

例如,^(T|t)he 匹配以 Thethe 开头的字符串。

"(T|t)he" => The car is parked in the garage.
1
2
3
4
P("The car is parked in the garage.","(T|t)he");
输出
The
the
"^(T|t)he" => The car is parked in the garage.
1
2
3
P("The car is parked in the garage.","^(T|t)he");
输出
The

$

同理于 ^ 号,$ 号用来匹配字符是否是最后一个。

例如,(at\.)$ 匹配以 at. 结尾的字符串。

"(at\.)" => The fat cat. sat. on the mat.
1
2
3
4
5
P("The fat cat. sat. on the mat.","(at\\.)");
输出
at.
at.
at.
"(at\.)$" => The fat cat. sat. on the mat.
1
2
3
P("The fat cat. sat. on the mat.","(at\\.)$"); //结尾
输出
at.

简写字符集

正则表达式提供一些常用的字符集简写。如下:

简写 描述
. 除换行符外的所有字符
\w 匹配所有字母数字,等同于 [a-zA-Z0-9_]
\W 匹配所有非字母数字,即符号,等同于: [^\w]
\d 匹配数字: [0-9]
\D 匹配非数字: [^\d]
\s 匹配所有空格字符,等同于: [\t\n\f\r\p{Z}]
\S 匹配所有非空格字符: [^\s]
\f 匹配一个换页符
\n 匹配一个换行符
\r 匹配一个回车符
\t 匹配一个制表符
\v 匹配一个垂直制表符
\p 匹配 CR/LF(等同于 \r\n),用来匹配 DOS 行终止符

零宽度断言如下:

符号 描述
?= 正先行断言-存在
?! 负先行断言-排除
?<= 正后发断言-存在
?<! 负后发断言-排除

4.1 ?=... 正先行断言 后面必须符合要求

?=... 正先行断言,表示第一部分表达式之后必须跟着 ?=...定义的表达式。

返回结果只包含满足匹配条件的第一部分表达式。
定义一个正先行断言要使用 ()。在括号内部使用一个问号和等号: (?=...)

正先行断言的内容写在括号中的等号后面。
例如,表达式 (T|t)he(?=\sfat) 匹配 Thethe,在括号中我们又定义了正先行断言 (?=\sfat) ,即 Thethe 后面紧跟着 (空格)fat

"(T|t)he(?=\sfat)" => The fat cat sat on the mat.
1
2
3
P("The fat cat sat on the mat.","(T|t)he(?=\\sfat)"); // s代表空格 T或the后面必须是空格fat
输出
The

?!... 负先行断言 后面必须符合要求(取反)

负先行断言 ?! 用于筛选所有匹配结果,筛选条件为 其后不跟随着断言中定义的格式。
正先行断言 定义和 负先行断言 一样,区别就是 = 替换成 ! 也就是 (?!...)

表达式 (T|t)he(?!\sfat) 匹配 Thethe,且其后不跟着 (空格)fat

"(T|t)he(?!\sfat)" => The fat cat sat on the mat.
1
2
3
P("The fat cat sat on the mat.","(T|t)he(?!\\sfat)"); // s代表空格 T或the后面必须不是空格fat
输出
the

?<= ... 正后发断言 前面必须符合要求

正后发断言 记作(?<=...) 用于筛选所有匹配结果,筛选条件为 其前跟随着断言中定义的格式。
例如,表达式 (?<=(T|t)he\s)(fat|mat) 匹配 fatmat,且其前跟着 Thethe

"(?<=(T|t)he\s)(fat|mat)" => The fat cat sat on the mat.
1
2
3
4
P("The fat cat sat on the mat.","(?<=(T|t)he\\s)(fat|mat)"); // s代表空格 匹配fat或者mat 前面必须是T|the空格
输出
fat
mat

?<!... 负后发断言 前面必须不符合要求

负后发断言 记作 (?<!...) 用于筛选所有匹配结果,筛选条件为 其前不跟随着断言中定义的格式。
例如,表达式 (?<!(T|t)he\s)(cat) 匹配 cat,且其前不跟着 Thethe

"(?<!(T|t)he\s)(cat)" => The cat sat on cat.
1
2
3
4
5
P("The fat cat sat on the mat.","(?<!(T|t)he\\s)(cat)"); // s代表空格 匹配fat或者mat 前面必须不是T|the空格
输出
99
97
10

标志

标志也叫模式修正符,因为它可以用来修改表达式的搜索结果。
这些标志可以任意的组合使用,它也是整个正则表达式的一部分。

标志 描述
i 忽略大小写。
g 全局搜索。
m 多行修饰符:锚点元字符 ^ $ 工作范围在每行的起始。

忽略大小写 (Case Insensitive)

修饰语 i 用于忽略大小写。
例如,表达式 /The/gi 表示在全局搜索 The,在后面的 i 将其条件修改为忽略大小写,则变成搜索 theTheg 表示全局搜索。

"/The/gi" => The fat cat sat on the mat.

修饰符 g 常用于执行一个全局搜索匹配,即(不仅仅返回第一个匹配的,而是返回全部)。
例如,表达式 /.(at)/g 表示搜索 任意字符(除了换行)+ at,并返回全部结果。

"/.(at)/" => The fat cat sat on the mat.

在线练习

"/.(at)/g" => The fat cat sat on the mat.

在线练习

多行修饰符 (Multiline)

多行修饰符 m 常用于执行一个多行匹配。

像之前介绍的 (^,$) 用于检查格式是否是在待检测字符串的开头或结尾。但我们如果想要它在每行的开头和结尾生效,我们需要用到多行修饰符 m

例如,表达式 /at(.)?$/gm 表示小写字符 a 后跟小写字符 t ,末尾可选除换行符外任意字符。根据 m 修饰符,现在表达式匹配每行的结尾。

"/.at(.)?$/" => The fat
                cat sat
                on the mat.
"/.at(.)?$/gm" => The fat
                  cat sat
                  on the mat.

贪婪匹配与惰性匹配 (Greedy vs lazy matching)

正则表达式默认采用贪婪匹配模式,在该模式下意味着会匹配尽可能长的子串。我们可以使用 ? 将贪婪匹配模式转化为惰性匹配模式。

"/(.*at)/" => The fat cat sat on the mat. 
"/(.*?at)/" => The fat cat sat on the mat.