2020.07-2020.09 学习总结

2020.07-2020.09 学习总结

[TOC]


C++

<返回目录>

C++ 基于容器(docker)的开发环境配置

<返回目录>

配置ODBC

安装配置之前,需要先大概了解一下 MyODBC 的架构,MyODBC 体系结构建立在 5 个组件上,如下图所示:

Driver Manager
负责管理应用程序和驱动程序间的通信,主要功能包括:解析 DSN (数据源名称,ODBC 的数据源名称在 odbc.ini 文件中配置),加载和卸载驱动程序,处理 ODBC 调用,将其传递给驱动程序。

ODBC.INI
odbc.ini 是 ODBC 配置文件,记录了连接到服务器所需的驱动信息和数据库信息。Driver Manager 将使用它来确定加载哪个驱动程序(使用数据源名 DSN )。驱动程序将根据指定的DSN来读取连接参数。

Connector/ODBC(MyODBC驱动程序)
实现 ODBC API 所提供的功能,它负责处理 ODBC 函数调用,将 SQL 请求提交给 MySQL 服务器,并将结果返回给应用程序。

在 Linux 下配置 mysql ODBC 需要有以下步骤:

1
2
3
1. 安装 Driver Manager,本案例使用 unixODBC 来作为 Driver Manager。
2. 安装 MySQL 驱动程序,本案例使用 Connector/ODBC。
3. 配置 ODBC.INI

第一步:下载安装包

需要下载两个安装包 unixODBC 2.3.0mysql Connector/ODBC 3.51
unixODBC 源码包:ftp://ftp.unixodbc.org/pub/unixODBC/unixODBC-2.3.0.tar.gz
mysql Connector/ODBC 源码包:http://dev.mysql.com/downloads/connector/odbc/3.51.html%23downloads
选择

1
2
3
版本:5.1.11
平台:Oracle&Red Hat Linux6
下载:mysql-connector-odbc-5.1.11-linux-el6-x86-64bit.tar.gz

第二步:安装 unixODBC

1
2
3
4
5
tar -zxvf unixODBC-2.3.4.tar.gz
cd unixODBC-2.3.4
./configure --prefix=/usr/local/unixODBC-2.3.4 --includedir=/usr/include --libdir=/usr/local/lib -bindir=/usr/bin --sysconfdir=/usr/local/etc
make
make install

安装完成后,可以在/usr/bin目录下有下面的文件

1
2
3
4
5
-rwxr-xr-x 1 root root      75312 Nov 1 16:22 odbcinst
-rwxr-xr-x 1 root root 10922 Nov 1 16:22 odbc_config
-rwxr-xr-x 1 root root 37650 Nov 1 16:22 iusql
-rwxr-xr-x 1 root root 44400 Nov 1 16:22 isql
-rwxr-xr-x 1 root root 95903 Nov 1 16:22 dltest

在/usr/local/lib目录下面有这些文件

1
2
3
4
5
6
7
8
9
10
11
12
-rwxr-xr-x 1 root root 422955 Nov 1 16:22 libodbcinst.so.1.0.0
lrwxrwxrwx 1 root root 20 Nov 1 16:22 libodbcinst.so.1 -> libodbcinst.so.1.0.0
lrwxrwxrwx 1 root root 20 Nov 1 16:22 libodbcinst.so -> libodbcinst.so.1.0.0
-rwxr-xr-x 1 root root 981 Nov 1 16:22 libodbcinst.la
-rwxr-xr-x 1 root root 169157 Nov 1 16:22 libodbc.so.1.0.0
lrwxrwxrwx 1 root root 16 Nov 1 16:22 libodbc.so.1 -> libodbc.so.1.0.0
lrwxrwxrwx 1 root root 16 Nov 1 16:22 libodbc.so -> libodbc.so.1.0.0
-rwxr-xr-x 1 root root 957 Nov 1 16:22 libodbc.la
-rwxr-xr-x 1 root root 489405 Nov 1 16:22 libodbccr.so.1.0.0
lrwxrwxrwx 1 root root 18 Nov 1 16:22 libodbccr.so.1 -> libodbccr.so.1.0.0
lrwxrwxrwx 1 root root 18 Nov 1 16:22 libodbccr.so -> libodbccr.so.1.0.0
-rwxr-xr-x 1 root root 969 Nov 1 16:22 libodbccr.la

第三步:安装 mysql Connector/ODBC

1
2
3
4
5
tar -zxvf mysql-connector-odbc-5.1.11-linux-el6-x86-64bit.tar.gz
cd mysql-connector-odbc-5.1.11-linux-el6-x86-64bit/lib
cp libmyodbc5.so /usr/local/lib
cd ..
cd bin

注册驱动

1
2
3
./myodbc-installer -d -a -n "MySQL ODBC 5.1 Driver" -t "DRIVER=/usr/local/lib/libmyodbc5.so;SETUP=/usr/local/lib/libmyodbc5.so"

//odbc 5.3及以上是libmyodbc5a.so和libmyodbc5w.so。其中c5a是Ansi版,c5w是Unicode版

假如注册的时候报错找不到libodbc.so.2,但是之前确实装成功了unixodbc,可能是因为系统找不到/usr/local/lib库目录,需要添加系统搜索库目录路径:

1
2
3
4
5
6
7
vi /etc/ld.so.conf

//将/usr/local/lib直接添加在配置文件里

ldconfig

//重新缓存配置文件(为了加快程序执行时对共享库的定位速度,避免使用搜索路径查找共享库的低效率,所以是直接读取库列表文件/etc/ld.so.cache缓存文件并从中进行搜索的)

第四步:配置 ODBC.INI

1
2
3
4
5
6
7
8
9
10
odbcinst -j

unixODBC 2.3.1
DRIVERS............: /etc/odbcinst.ini
SYSTEM DATA SOURCES: /etc/odbc.ini
FILE DATA SOURCES..: /etc/ODBCDataSources
USER DATA SOURCES..: /root/.odbc.ini
SQLULEN Size.......: 8
SQLLEN Size........: 8
SQLSETPOSIROW Size.: 8

编辑文件/etc/odbc.ini,把下面的内容加上去。不同版本mysql驱动的配置方法,有细微差异。此处使用的版本是mysql Connector 3.51

1
2
3
4
5
6
7
8
9
10
[mysqlDSN]
Driver = /usr/local/lib/libmyodbc5.so
Description = MyODBC 5 Driver DSN
SERVER = 172.31.108.133
PORT = 3306
USER = root
Password = 123456
Database = PM
OPTION = 3
charset = UTF8

第五步:设置环境变量

1
2
export DBCINI=/usr/local/etc/odbc.ini
export DBCSYSINI=/usr/local/etc

第六步:重启电脑

1
reboot

第七步:测试ODBC配置是否成功
isql 是 unixODBC 带的一个 ODBC 客户端访问工具,使用isql +数据源名来访问目标数据库。如果 ODBC 配置正确,会显示下面的界面。在SQL>提示符下输入 SQL 语句查询数据库。

1
2
3
4
5
6
7
8
9
10
isql mysqlDSN

+---------------------------------------+
| Connected! |
| |
| sql-statement |
| help [tablename] |
| quit |
| |
+---------------------------------------+

遇到的问题:

  • 问题1
    在第三步安装 mysql connector/ODBC 中的注册驱动中,我总是会出现./myodbc-installer: error while loading shared libraries: libodbc.so.2: cannot open shared object file: No such file or directory.这种错误,后来发现错误有两点:
    1. 我下载的是 mysql-connector-5.3.6 ,可能版本比较高,而我初次下载用的是unixODBC-2.3.0,版本较低,里面没有 libodbc.so.2 这个库文件(可以用find / -name libodbc.so.2来查)。后来下载了一个 unixODBC-2.3.4 就好了。
    2. 改了版本之后,我发现还是有这个错误,在网上查了下,说是程序查找默认路径为 /lib 和 /usr/lib,而我的 libmyodbc5w.so 和 libmmyodbc5a.so 都在 /usr/local/lib 中,所以查不到,所以需要设置一下共享库路径,以下我贴一下网上查的内容:
1
2
3
4
cat /etc/ld.so.conf
include ld.so.conf.d/*.conf
echo "/usr/local/lib" >> /etc/ld.so.conf
ldconfig
  • 问题2
    如果共享库文件安装到了其它非/lib/usr/lib目录下,但是又不想在/etc/ld.so.conf中加路径(或者是没有权限加路径)。那可以 export 一个全局变量LD_LIBRARY_PATH,然后运行程序的时候就会去这个目录中找共享库。LD_LIBRARY_PATH的意思是告诉 loader 在哪些目录中可以找到共享库。
    可以设置多个搜索目录,这些目录之间用冒号分隔开。
    比如:
    安装了一个 mysql 到/usr/local/mysql目录下,其中有一大堆库文件在/usr/local/mysql/lib下面,则可以在 .bashrc 或 .bash_profile 或 shell 里加入以下语句即可:

    1
    export LD_LIBRARY_PATH=/usr/local/mysql/lib:$LD_LIBRARY_PATH

    一般来讲这只是一种临时的解决方案,在没有权限或临时需要的时候使用。

  • 问题3
    如果程序需要的库文件比系统目前存在的村文件版本低,可以做一个链接
    比如:

    1
    2
    error while loading shared libraries: libncurses.so.4: cannot open shared
    object file: No such file or directory
    1
    2
    3
    ls /usr/lib/libncu*
    /usr/lib/libncurses.a /usr/lib/libncurses.so.5
    /usr/lib/libncurses.so /usr/lib/libncurses.so.5.3

    可见虽然没有 libncurses.so.4,但有 libncurses.so.5,是可以向下兼容的
    建一个链接就好了

    1
    ln -s  /usr/lib/libncurses.so.5.3  /usr/lib/libncurses.so.4
  • 问题4
    isql 连接数据库失败,重新注册驱动:

    1
    2
    /usr/bin/myodbc-installer  -d -a -n "MySQL_UNICODE"  -t "DRIVER=/usr/lib64/libmyodbc8w.so;SETUP=/usr/lib64/libmyodbc8w.so"
    /usr/bin/myodbc-installer -d -a -n "MySQL_ANSI" -t "DRIVER=/usr/lib64/libmyodbc8a.so;SETUP=/usr/lib64/libmyodbc8a.so"

    使用 rpm 命令查看 rpm 包的内容

    1
    rpm -qpl xxx.rpm

    可以看到mysql-connector-odbc-8.0.20-1.el7.x86_64.rpm的包内容

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    warning: mysql-connector-odbc-8.0.20-1.el7.x86_64.rpm: Header V3 DSA/SHA1 Signature, key ID 5072e1f5: NOKEY
    /usr/bin/myodbc-installer
    /usr/lib64/libmyodbc8a.so
    /usr/lib64/libmyodbc8w.so
    /usr/share/doc/mysql-connector-odbc-8.0.20
    /usr/share/doc/mysql-connector-odbc-8.0.20/ChangeLog
    /usr/share/doc/mysql-connector-odbc-8.0.20/INFO_BIN
    /usr/share/doc/mysql-connector-odbc-8.0.20/INFO_SRC
    /usr/share/doc/mysql-connector-odbc-8.0.20/LICENSE.txt
    /usr/share/doc/mysql-connector-odbc-8.0.20/README.txt

    可以知道 rpm 包 安装的时候各个基础件的安装位置。

NGINX 的配置与基础命令

nginx 配置

查看 nginx 配置文件

1
2
cat /etc/nginx/nginx.conf
cat /etc/nginx/conf.d/xxxxxxxx.conf

可以看到 stdname 对应的监听端口设置 nginx 监听 18026 并转发至 stdnameSvr 的 监听端口 19026。

1
2
3
4
5
6
7
8
9
10
11
server {
listen 18026;
server_name localhost;

location /stdname/ {
fastcgi_pass 127.0.0.1:19026;
fastcgi_index index.cgi;
#fastcgi_param SCRIPT_FILENAME fcgi$fastcgi_script_name;
include fastcgi_params;
}
}

验证 nginx 配置文件是否正确

进入 nginx 安装目录 sbin 下,输入命令

1
./nginx -t

看到如下显示

1
2
nginx: the configuration file /.../nginx.conf syntax is ok
nginx: configuration file /.../nginx.conf test is successful

说明配置文件正确!

运行 nginx

1
/path_of_nginx/nginx -c /path_of_nginx.conf/nginx.conf

-c:指定 nginx 运行时使用的 conf 文件路径
-t:加上-t可以测试 nginx 配置是否正确

停止 nginx

查看进程号然后杀死进程

1
2
3
4
5
ps -ef | grep nginx
kill -QUIT <pid_of_nginx> //从容停止
kill -TERM <pid_of_nginx> //快速停止
kill -INT <pid_of_nginx> //快速停止
kill -9 nginx //强制停止

重启 nginx

方法一:
找到 nginx 可执行文件路径,然后输入命令:

1
nginx -s reload

方法二:
查找当前 nginx 进程号,然后输入命令:

1
kill -HUP <pid_of_nginx>

实现重启 nginx 服务。

Docker 端口映射

1
docker run -it -p 8080:18026 <REPOSITORY>:<TAG> /bin/bash

-p:是容器内部端口绑定到指定的主机端口。这里指将主机的8080端口映射到容器的18026端口。


1
docker run -it -p 127.0.0.1:8080:18026 <REPOSITORY>:<TAG> /bin/bash

这样我们就可以通过访问 127.0.0.1:8080 来访问容器的 18026 端口。


上面的例子中,默认都是绑定 tcp 端口,如果要绑定 UDP 端口,可以在端口后面加上 /udp。

1
docker run -it -p 127.0.0.1:8080:18026/udp <REPOSITORY>:<TAG> /bin/bash

docker port <CONTAINER ID> <PORT>命令可以让我们快捷地查看端口的绑定情况。

启动微服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
git clone --recurse-submodules https://gitlab.xxxxxxxx.net/.../*.git
//带这个参数,才会把 public 下载到子目录里面去

cd /path_of_project/

sh build.sh

cd bin/root_of_work_dir/

export VEHICLE_DATA_CONFIG=/root_of_work_dir/vehicle/config/config.xml
//代码中有对 VEHICLE_DATA_CONFIG 的宏定义,修改为本地路径

spawn_fcgi -a 127.0.0.1 -p 19026 -C 25 -U nginx -f stdnameSvr -F 1
//运行 stdnameSvr 服务

netstat -ntpl
//查看 nginx 和 stdnameSvr 服务是否均已开启

注释:****spawn-fcgi 用法了解

spawn-fcgi 是一个小程序,作用是管理 fast-cgi 进程。

用 spawn 启动 FCGI 程序的方式为:

1
./spawn-fcgi -a 127.0.0.1 -p 8080 -F ${count} -f ${webroot}/bin/demo.fcgi

这样就会启动 count 个 demo.fcgi 程序,他们共同监听同一个 listen 端口 8080,从而提供服务。

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
./spawn_fcgi -h
Usage: spawn-fcgi [options] [-- <fcgiapp> [fcgi app arguments]]

spawn-fcgi v1.6.5 - spawns FastCGI processes

Options:
-f <path> filename of the fcgi-application (deprecated; ignored if
<fcgiapp> is given; needs /bin/sh)
-d <directory> chdir to directory before spawning
-a <address> bind to IPv4/IPv6 address (defaults to 0.0.0.0)
-p <port> bind to TCP-port
-s <path> bind to Unix domain socket
-M <mode> change Unix domain socket mode (octal integer, default: allow
read+write for user and group as far as umask allows it)
-C <children> (PHP only) numbers of childs to spawn (default: not setting
the PHP_FCGI_CHILDREN environment variable - PHP defaults to 0)
-F <children> number of children to fork (default 1)
-b <backlog> backlog to allow on the socket (default 1024)
-P <path> name of PID-file for spawned process (ignored in no-fork mode)
-n no fork (for daemontools)
-v show version
-?, -h show this help
(root only)
-c <directory> chroot to directory
-S create socket before chroot() (default is to create the socket
in the chroot)
-u <user> change to user-id
-g <group> change to group-id (default: primary group of user if -u
is given)
-U <user> change Unix domain socket owner to user-id
-G <group> change Unix domain socket group to group-id

C++ OTL 流处理包

<返回目录>
otl的源码只有一个头文件——otlv4.h。下面以一个例子来说明如何使用otl。

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
#include <otlv4.h>

#define OTL_ORA10G

void CAboutDlg::OnBnClickedOk()
{
// TODO: 在此添加控件通知处理程序代码
otl_connect OracleDb; // 定义一个oracle数据库的连接对象

OracleDb.otl_initialize(TRUE);// 以线程安全模式初始化OCI环境

std::string szConnectString = _T("system/zjc@ORCL");

try
{
// 连接数据库
OracleDb.rlogon(szConnectString.c_str(), 1);
// 查询数据库中所有用户
std::string strSql = _T("SELECT username FROM dba_users");
otl_stream i(1024, // buffer size
strSql.c_str(),
OracleDb // connect object
);

int nNumUser = 0;
TCHAR szNum[64];
while (!i.eof())// while not end-of-data
{
i >> szNum; //获取单个用户名
nNumUser++;
}
CString strNum;
strNum.Format(("当前oracle数据库用户个数为:%d"), nNumUser);
AfxMessageBox(strNum);
}
catch (otl_exception &p)
{
TRACE(_T("Oracle connecterror(msg:%s, stm_text: %s, sqlstate: %s, var_info: %s)"), p.msg, p.stm_text,
p.sqlstate, p.var_info);
}

OnOK();
}

上面代码例子连接Oracle数据库用到了rlogon()函数,调用它时需要为它提供一个连接字符串,一般是这样的:

1
[User Name]/[Password]@[TNS Alias]

这里的TNS Alias指在tnsnames.ora中配置TNS名,比如我的tnsnames.ora里有以下的配置:

1
2
# tnsnames.ora Network Configuration File: D:\oracle\product\10.2.0\db_1\network\admin\tnsnames.ora
# Generated by Oracle configuration tools.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ORCL =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = zjc)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = orcl)
)
)

EXTPROC_CONNECTION_DATA =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1))
)
(CONNECT_DATA =
(SID = PLSExtProc)
(PRESENTATION = RO)
)
)

那么TNS Alias就是ORCL

此外需要注意的是使用otl连接oracle数据库需要链接oci.lib,也就是说需要包含它的头文件和库文件路径。

Vector 遍历的几种方法

<返回目录>

vector<int> v1{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10};

一、通过数组下标遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
for (size_t i = 0; i < v1.size(); i++)
{
cout << v1[i] << "; ";
}
cout << endl;

for (size_t i = 0; i < v1.size(); i++)
{
cout << v1.at(i) << "; ";
}
cout << endl;

2; 3; 4; 5; 6; 7; 8; 9; 10; 10; 10;
1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 10;

二、通过迭代器遍历

1
2
3
4
5
6
for (vector<int>::iterator iter = v1.begin(); iter != v1.end(); iter++)
{
std::cout << *iter << "; ";
}
cout << endl;
1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 10;

三、C++11标准,auto关键字遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
for (auto iter = v1.begin(); iter != v1.end(); iter++)
{
cout << *iter << "; ";
}
cout << endl;

for (auto i : v1)
{
cout << v1[i] << "; ";
}
cout << endl;
1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 10;
1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 10;

四、for_each加函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <vector>
#include<algorithm>

using namespace std;

template<typename T>
void printer(const T& val)
{
cout << val << "; ";
}

void main()
{
for_each(v1.cbegin(), v1.cend(), printer<int>);
cout << endl;
}

1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 10;

C++ 计时方法——chrono

<返回目录>
传统计时方法:

1
2
3
4
5
6
7
#include <ctime>
using namespace std;

clock_t start = clock();
// do something...
clock_t end = clock();
cout << "花费了" << (double)(end - start) / CLOCKS_PER_SEC << "秒" << endl;

此方法可以精确到毫秒,输出样例:花费了0.123秒

C++11 最佳计时方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <chrono>   
using namespace std;
using namespace chrono;

auto start = system_clock::now();
// do something...
auto end = system_clock::now();
auto duration = duration_cast<microseconds>(end - start);
cout << "花费了" << double(duration.count()) * microseconds::period::num / microseconds::period::den << "秒" << endl;

//duration_cast< > 表示类型转换
//microseconds 表示微妙。除此之外,还有五种时间单位:hours, minutes, seconds, milliseconds, nanoseconds
//num 和 den分别表示分子(numerator)和分母(denominator)。在我给出的代码中,num等于1, den等于1,000,000
//count( ) 用来返回时间

其他开发过程中可能会遇到的坑

<返回目录>

1
public protected private virtual const override explicit extern
  • 以上限定词的作用以及继承关系的嵌套需要更加明晰,很容易被这些限定词把逻辑弄乱。
1
2
CurlCXX curl(url, 1); //1s timeout
curl.post(body);
  • 注意学会curl发包的用法,并且post时,body当中要注意fastcgi框架当中约定了post数据格式为x-www-form-urlencoded/form-data,因此一定要注意body里面的数据,单个字段内不能出现容易导致解析错误的'&'字符,若不得不包含'&'字符,则要用转义字符'\&'包起来,否则会导致参数错误。
1
2
3
const CallRecord *app;
app = app_ptr();
const_cast<CallRecord *>(app)->reload_cache();
  • 注意对const类型的对象操作时,需要用const_cast<XXXXXX>对该对象进行强制类型转换。

MySQL

<返回目录>

SQL SELECT DISTINCT 语句

<返回目录>
在表中,一个列可能会包含多个重复值,有时您也许希望仅仅列出不同(distinct)的值。DISTINCT 关键词用于返回唯一不同的值。

SQL SELECT DISTINCT 语法:

1
2
SELECT DISTINCT column_name,column_name
FROM table_name;

SQL UPDATE 语句

<返回目录>
UPDATE 语句用于更新表中已存在的记录。

SQL UPDATE 语法:

1
2
3
UPDATE table_name
SET column1=value1,column2=value2,...
WHERE some_column=some_value;

请注意 : SQL UPDATE 语句中的 WHERE 子句!WHERE 子句规定哪条记录或者哪些记录需要更新。如果您省略了 WHERE 子句,所有的记录都将被更新!

SQL DELETE 语句

<返回目录>
DELETE 语句用于删除表中的行(记录)。

SQL DELETE 语法:

1
2
DELETE FROM table_name
WHERE some_column=some_value;

请注意 : SQL DELETE 语句中的 WHERE 子句!WHERE 子句规定哪条记录或者哪些记录需要删除。如果您省略了 WHERE 子句,所有的记录都将被删除!

SQL REGEXP 语句

<返回目录>
作为一个更为复杂的示例,正则表达式 B[an]*s 匹配下述字符串中的任何一个:Bananas,Baaaaas,Bs,以及以 B 开始,以 s 结束、并在其中包含任意数目 a 或 n 字符的任何其他字符串。

以下是可用于随 REGEXP 操作符的表的模式。

应用示例,查找用户表中 Email 格式错误的用户记录:

1
2
3
SELECT * 
FROM users
WHERE email NOT REGEXP '^[A-Z0-9._%-]+@[A-Z0-9.-]+.[A-Z]{2,4}$'

MySQL 数据库中正则表达式的语法,主要包括各种符号的含义。

^ 字符

匹配字符串的开始位置,如 ^a 表示以字母 a 开头的字符串。

1
2
3
4
5
6
7
8
mysql> SELECT 'xxxyyy' REGEXP '^xx';

+-----------------------+
| 'xxxyyy' REGEXP '^xx' |
+-----------------------+
| 1 |
+-----------------------+
1 row in set (0.00 sec)

查询 xxxyyy 字符串中是否以 xx 开头,结果值为 1,表示值为 true,满足条件。

$ 字符

匹配字符串的结束位置,如 X$ 表示以字母 X 结尾的字符串。

. 字符

这个字符就是英文下的点,它匹配任何一个字符,包括回车、换行等。

* 字符

星号匹配 0 个或多个字符,在它之前必须有内容。如:

1
mysql> SELECT 'xxxyyy' REGEXP 'x*';

这个 SQL 语句,正则匹配为 true。

+ 字符

加号匹配 1 个或多个字符,在它之前也必须有内容。加号跟星号的用法类似,只是星号允许出现 0 次,加号则必须至少出现一次。

? 字符

问号匹配 0 次或 1 次。

实例:
查询找到所有的名字以 st 开头:

1
2
3
4
5
6
7
8
9
mysql> SELECT name FROM person_tbl WHERE name REGEXP '^st';
//查询找到所有的名字以 ok 结尾:

mysql> SELECT name FROM person_tbl WHERE name REGEXP 'ok$';
//查询找到所有的名字包函 mar 的字符串:

mysql> SELECT name FROM person_tbl WHERE name REGEXP 'mar';
//查询找到所有名称以元音开始和 ok 结束的:
mysql> SELECT name FROM person_tbl WHERE name REGEXP '^[aeiou]|ok$';

一个正则表达式中的可以使用以下保留字。

^
所匹配的字符串以后面的字符串开头:

1
2
mysql> SELECT "fonfo" REGEXP "^fo$"; -> 0(表示不匹配) 
mysql> SELECT "fofo" REGEXP "^fo"; -> 1(表示匹配)

$
所匹配的字符串以前面的字符串结尾:

1
2
mysql> SELECT "fono" REGEXP "^fono$"; -> 1(表示匹配) 
mysql> SELECT "fono" REGEXP "^fo$"; -> 0(表示不匹配)

.
匹配任何字符(包括新行):

1
2
mysql> SELECT "fofo" REGEXP "^f.*"; -> 1(表示匹配) 
mysql> SELECT "fonfo" REGEXP "^f.*"; -> 1(表示匹配)

a*
匹配任意多个 a(包括空串):

1
2
3
mysql> SELECT "Ban" REGEXP "^Ba*n"; -> 1(表示匹配) 
mysql> SELECT "Baaan" REGEXP "^Ba*n"; -> 1(表示匹配)
mysql> SELECT "Bn" REGEXP "^Ba*n"; -> 1(表示匹配)

a+
匹配任意多个 a(不包括空串):

1
2
mysql> SELECT "Ban" REGEXP "^Ba+n"; -> 1(表示匹配) 
mysql> SELECT "Bn" REGEXP "^Ba+n"; -> 0(表示不匹配)

a?
匹配一个或零个 a:

1
2
3
mysql> SELECT "Bn" REGEXP "^Ba?n"; -> 1(表示匹配) 
mysql> SELECT "Ban" REGEXP "^Ba?n"; -> 1(表示匹配)
mysql> SELECT "Baan" REGEXP "^Ba?n"; -> 0(表示不匹配)

de|abc
匹配 de 或 abc:

1
2
3
4
5
6
mysql> SELECT "pi" REGEXP "pi|apa"; -> 1(表示匹配) 
mysql> SELECT "axe" REGEXP "pi|apa"; -> 0(表示不匹配)
mysql> SELECT "apa" REGEXP "pi|apa"; -> 1(表示匹配)
mysql> SELECT "apa" REGEXP "^(pi|apa)$"; -> 1(表示匹配)
mysql> SELECT "pi" REGEXP "^(pi|apa)$"; -> 1(表示匹配)
mysql> SELECT "pix" REGEXP "^(pi|apa)$"; -> 0(表示不匹配)

(abc)*
匹配任意多个abc(包括空串):

1
2
3
mysql> SELECT "pi" REGEXP "^(pi)*$"; -> 1(表示匹配) 
mysql> SELECT "pip" REGEXP "^(pi)*$"; -> 0(表示不匹配)
mysql> SELECT "pipi" REGEXP "^(pi)*$"; -> 1(表示匹配)

{1}
{2,3}
这是一个更全面的方法,它可以实现前面好几种保留字的功能。
a* 可以写成 a{0,}
a+ 可以写成 a{1,}
a? 可以写成 a{0,1}

在 {} 内只有一个整型参数 i,表示字符只能出现 i 次;在 {} 内有一个整型参数 i,后面跟一个 ,,表示字符可以出现 i 次或 i 次以上;在 {} 内只有一个整型参数 i,后面跟一个 ,,再跟一个整型参数 j, 表示字符只能出现 i 次以上,j 次以下(包括 i 次和 j 次)。其中的整型参数必须大于等于 0,小于等于 RE_DUP_MAX(默认是 255)。 如果有两个参数,第二个必须大于等于第一个。

[a-dX] 匹配 “a”、“b”、“c”、“d”“X”
[^a-dX] 匹配除 “a”、“b”、“c”、“d”、“X” 以外的任何字符。

“[”、“]”必须成对使用:

1
2
3
4
5
6
mysql> SELECT "aXbc" REGEXP "[a-dXYZ]"; -> 1(表示匹配) 
mysql> SELECT "aXbc" REGEXP "^[a-dXYZ]$"; -> 0(表示不匹配)
mysql> SELECT "aXbc" REGEXP "^[a-dXYZ]+$"; -> 1(表示匹配)
mysql> SELECT "aXbc" REGEXP "^[^a-dXYZ]+$"; -> 0(表示不匹配)
mysql> SELECT "gheis" REGEXP "^[^a-dXYZ]+$"; -> 1(表示匹配)
mysql> SELECT "gheisa" REGEXP "^[^a-dXYZ]+$"; -> 0(表示不匹配)

SQL IN 操作符

<返回目录>
IN 操作符允许您在 WHERE 子句中规定多个值。

SQL IN 语法:

1
2
3
SELECT column_name(s)
FROM table_name
WHERE column_name IN (value1,value2,...);

SQL BETWEEN 操作符

<返回目录>
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。

SQL BETWEEN 语法:

1
2
3
SELECT column_name(s)
FROM table_name
WHERE column_name BETWEEN value1 AND value2;

SQL 别名

<返回目录>
通过使用 SQL,可以为表名称或列名称指定别名。基本上,创建别名是为了让列名称的可读性更强。

列的 SQL 别名语法:

1
2
SELECT column_name AS alias_name
FROM table_name;

表的 SQL 别名语法:

1
2
SELECT column_name(s)
FROM table_name AS alias_name;

SQL JOIN

<返回目录>
SQL JOIN 子句用于把来自两个或多个表的行结合起来,基于这些表之间的共同字段。

INNER JOIN:如果表中有至少一个匹配,则返回行
LEFT JOIN:即使右表中没有匹配,也从左表返回所有的行
RIGHT JOIN:即使左表中没有匹配,也从右表返回所有的行
FULL JOIN:只要其中一个表中存在匹配,则返回行

SQL INNER JOIN 关键字

INNER JOIN 关键字在表中存在至少一个匹配时返回行。

SQL INNER JOIN 语法:

1
2
3
4
SELECT column_name(s)
FROM table1
INNER JOIN table2
ON table1.column_name=table2.column_name;

或:

1
2
3
4
SELECT column_name(s)
FROM table1
JOIN table2
ON table1.column_name=table2.column_name;

注释:INNER JOIN 与 JOIN 是相同的。

SQL LEFT JOIN 关键字

LEFT JOIN 关键字从左表(table1)返回所有的行,即使右表(table2)中没有匹配。如果右表中没有匹配,则结果为 NULL。

SQL LEFT JOIN 语法:

1
2
3
4
SELECT column_name(s)
FROM table1
LEFT JOIN table2
ON table1.column_name=table2.column_name;

或:

1
2
3
4
SELECT column_name(s)
FROM table1
LEFT OUTER JOIN table2
ON table1.column_name=table2.column_name;

注释:在某些数据库中,LEFT JOIN 称为 LEFT OUTER JOIN。
注释:LEFT JOIN 关键字从左表(Websites)返回所有的行,即使右表(access_log)中没有匹配。

SQL RIGHT JOIN 关键字

RIGHT JOIN 关键字从右表(table2)返回所有的行,即使左表(table1)中没有匹配。如果左表中没有匹配,则结果为 NULL。

SQL RIGHT JOIN 语法:

1
2
3
4
SELECT column_name(s)
FROM table1
RIGHT JOIN table2
ON table1.column_name=table2.column_name;

或:

1
2
3
4
SELECT column_name(s)
FROM table1
RIGHT OUTER JOIN table2
ON table1.column_name=table2.column_name;

注释:在某些数据库中,RIGHT JOIN 称为 RIGHT OUTER JOIN。
注释:RIGHT JOIN 关键字从右表(Websites)返回所有的行,即使左表(access_log)中没有匹配。

SQL FULL OUTER JOIN 关键字

FULL OUTER JOIN 关键字只要左表(table1)和右表(table2)其中一个表中存在匹配,则返回行。

FULL OUTER JOIN 关键字结合了 LEFT JOIN 和 RIGHT JOIN 的结果。

SQL FULL OUTER JOIN 语法:

1
2
3
4
SELECT column_name(s)
FROM table1
FULL OUTER JOIN table2
ON table1.column_name=table2.column_name;

注释:FULL OUTER JOIN 关键字返回左表(Websites)和右表(access_log)中所有的行。如果 “Websites” 表中的行在 “access_log” 中没有匹配或者 “access_log” 表中的行在 “Websites” 表中没有匹配,也会列出这些行。
注释:MySQL中不支持 FULL OUTER JOIN

SQL UNION 操作符

<返回目录>
UNION 操作符用于合并两个或多个 SELECT 语句的结果集。

请注意,UNION 内部的每个 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每个 SELECT 语句中的列的顺序必须相同。

SQL UNION 语法:

1
2
3
SELECT column_name(s) FROM table1
UNION
SELECT column_name(s) FROM table2;

注释:默认地,UNION 操作符选取不同的值。如果允许重复的值,请使用 UNION ALL。

SQL UNION ALL 语法:

1
2
3
SELECT column_name(s) FROM table1
UNION ALL
SELECT column_name(s) FROM table2;

注释:UNION 结果集中的列名总是等于 UNION 中第一个 SELECT 语句中的列名。

SQL INSERT INTO SELECT 语句

<返回目录>
通过 SQL,您可以从一个表复制信息到另一个表。
INSERT INTO SELECT 语句从一个表复制数据,然后把数据插入到一个已存在的表中。目标表中任何已存在的行都不会受影响。

SQL INSERT INTO SELECT 语法:

1
2
3
4
5
6
7
8
9
//我们可以从一个表中复制所有的列插入到另一个已存在的表中:
INSERT INTO table2
SELECT * FROM table1;

//或者我们可以只复制希望的列插入到另一个已存在的表中:
INSERT INTO table2
(column_name(s))
SELECT column_name(s)
FROM table1;

MySQL 复制表(MySQL的SELECT INTO FROM 语句)

<返回目录>
复制表结构及其数据:

1
CREATE TABLE table_name_new AS SELECT * FROM table_name_old

只复制表结构:

1
CREATE TABLE table_name_new AS SELECT * FROM table_name_old WHERE 1=2;
  • 或者:
1
CREATE TABLE table_name_new LIKE table_name_old

只复制表数据:

  • 如果两个表结构一样:
1
INSERT INTO table_name_new SELECT * FROM table_name_old
  • 如果两个表结构不一样:
1
INSERT INTO table_name_new(column1,column2...) SELECT column1,column2... FROM table_name_old

SELECT INTO FROM 和 INSERT INTO SELECT 的区别:

主要区别:SELECT INTO FROM 要求目标表不存在,因为在插入时会自动创建;INSERT INTO SELECT FROM 要求目标表存在。

SELECT INTO FROM :将查询出来的数据整理到一张新表中保存,表结构与查询结构一致。

1
SELECT *(查询出来的结果) INTO newtable(新的表名)FROM WHERE (后续条件)

即,查询出来结果—>复制一张同结构的空表—>将数据拷贝进去。

INSERT INTO SELECT :为已经存在的表批量添加新数据。

1
INSERT INTO  (准备好的表) SELECT *(或者取用自己想要的结构)FROM 表名 WHERE 各种条件

即,指定一张想要插入数据的表格—>对数据进行加工筛选—>填入一张准备好的表格。

SQL 约束(Constraints)

<返回目录>
SQL 约束用于规定表中的数据规则。如果存在违反约束的数据行为,行为会被约束终止。

约束可以在创建表时规定(通过 CREATE TABLE 语句),或者在表创建之后规定(通过 ALTER TABLE 语句)。

SQL CREATE TABLE + CONSTRAINT 语法

1
2
3
4
5
6
7
CREATE TABLE table_name
(
column_name1 data_type(size) constraint_name,
column_name2 data_type(size) constraint_name,
column_name3 data_type(size) constraint_name,
....
);

在 SQL 中,我们有如下约束:

  • NOT NULL - 指示某列不能存储 NULL 值。
  • UNIQUE - 保证某列的每行必须有唯一的值。
  • PRIMARY KEY - (NOT NULLUNIQUE 的结合)。确保某列(或两个列多个列的结合)有唯一标识,有助于更容易更快速地找到表中的一个特定的记录。
  • FOREIGN KEY - 保证一个表中的数据匹配另一个表中的值的参照完整性。
  • CHECK - 保证列中的值符合指定的条件。
  • DEFAULT - 规定没有给列赋值时的默认值。

SQL ALTER TABLE 语句

<返回目录>
ALTER TABLE 语句用于在已有的表中添加、删除或修改列。

SQL ALTER TABLE 语法:

如需在表中添加列,请使用下面的语法:

1
2
ALTER TABLE table_name
ADD column_name datatype

如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):

1
2
ALTER TABLE table_name
DROP COLUMN column_name

要改变表中列的数据类型,请使用下面的语法:

1
2
ALTER TABLE table_name
MODIFY COLUMN column_name datatype

SQL AUTO INCREMENT 字段

<返回目录>
AUTO-INCREMENT 会在新记录插入表中时生成一个唯一的数字。

AUTO INCREMENT 字段
我们通常希望在每次插入新记录时,自动地创建主键字段的值。

SQL CREATE VIEW 语句

<返回目录>
在 SQL 中,视图是基于 SQL 语句的结果集的可视化的表。

视图包含行和列,就像一个真实的表。视图中的字段就是来自一个或多个数据库中的真实的表中的字段。

您可以向视图添加 SQL 函数、WHERE 以及 JOIN 语句,也可以呈现数据,就像这些数据来自于某个单一的表一样。

SQL CREATE VIEW 语法:

1
2
3
4
CREATE VIEW view_name AS
SELECT column_name(s)
FROM table_name
WHERE condition

注释:视图总是显示最新的数据!每当用户查询视图时,数据库引擎通过使用视图的 SQL 语句重建数据。

SQL 撤销视图

<返回目录>
您可以通过 DROP VIEW 命令来删除视图。

SQL DROP VIEW 语法:

1
DROP VIEW view_name

MySQL中修改表名,表属性名等操作

<返回目录>

1
2
3
4
5
ALTER TABLE 表名 CHANGE 原列名 新列名  类型; --修改表的列属性名
ALTER TABLE 表名 MODIFY 列名 类型 ; --修改表的类类型
ALTER TABLE 表名 DROP 列名; --删除表的某一列
ALTER TABLE 表名 ADD 列名 类型;--添加某一列
ALTER TABLE 表名 RENAME 新表名; --修改表名

其他的问题

<返回目录>

mysql清空表数据后如何让自增ID仍从1开始?

也就是说如何重排 auto_increment

两种方法:

1、清空表时使用truncate命令,而不用delete命令

1
TRUNCATE TABLE table_name ;

使用truncate命令的好处:

1)、速度快
2)、可以对自增 ID 进行重排,使自增 ID 仍从1开始计算

2、清空表数据后,使用alter修改表

1
ALTER TABLE table_name AUTO_INCREMENT = 1;

mysql 建立索引

INDEX idx_interface_name ( interface_name ) USING BTREE 建立B树索引

mysql 插入数据

如果对应元素有默认值,则可以,在 INSERT 时为空,不然会报错。

mysql 时间戳设置

DEFAULT CURRENT_TIMESTAMP 表示当插入数据的时候,该字段默认值为当前时间
ON UPDATE CURRENT_TIMESTAMP 在数据库数据有更新的时候UPDATE_TIME的时间会自动更新

mysql 主键自增设置

AUTO_INCREMENT 用于主键自动增长

Python

<返回目录>

python 读取 Excel 文档

<返回目录>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def read_excel(self, path):
try:
logger.info("begin read %s" % path)
# 读取 Excel 预处理动作↓,使用 xlrd 包将 Excel 文件读入 book 中
book = xlrd.open_workbook(path,encoding_override='utf-8')
data = dict()
sheets = book.sheets()
for cur in sheets:
sheet_name = cur.name
nrows = cur.nrows
ncols = cur.ncols
logger.info("nrows=%d,ncols=%d" % (nrows, ncols))
sheet_val = list()
for idx in range(0, nrows):
line = cur.row_values(idx)
# sheet_val 为对应该页面每行数据的 list 数据
sheet_val.append(line)
# data 为整个 Excel 文件每一张 sheet 的 Map 数据
data[sheet_name] = sheet_val
logger.info("read end, sheet=%d" % len(data))
return data
except Exception as e:
logger.info("read %s fail, err=%s" % (path, str(e)))
return None

python Excel 数据处理

<返回目录>
Excel 转换成 SQL 语句

单独拉出一列,在首行传入该函数后,复制到每一行,可拉取对应列的数据,并转换为 sql 语句。

1
=CONCATENATE("INSERT INTO table_name (list_1,list_2,list_3) VALUES ('",A1,"','",B1,"','",C1,"');")

Python 批量处理 Excel

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import pymysql
import xlrd

'''
连接数据库
args:db_name(数据库名称)
returns:db
'''


def mysql_link(db_name):
try:
db = pymysql.connect(host="xxx.xxx.xxx.xxx",
port=xxxx,
user="xxxxxx",
passwd="xxxxxx",
db=db_name,
charset='utf8')
except:
print("could not connect to mysql server")
return db


'''
读取excel函数
args:excel_file(excel文件,目录在py文件同目录)
returns:book
'''


def open_excel(excel_file):
try:
book = xlrd.open_workbook(excel_file) # 文件名,把文件与py文件放在同一目录下
except:
print("open excel file failed!")
return book


'''
执行插入操作
args:db_name(数据库名称)
table_name(表名称)
excel_file(excel文件名,把文件与py文件放在同一目录下)
'''


def store_to(db_name: object, table_name: object, excel_file: object) -> object:
db = mysql_link(db_name) # 打开数据库连接
cursor = db.cursor() # 使用 cursor() 方法创建一个游标对象 cursor
book = open_excel(excel_file) # 打开excel文件
sheets = book.sheet_names() # 获取所有sheet表名
for sheet in sheets:
sh = book.sheet_by_name(sheet) # 打开每一张表
row_num = sh.nrows
if row_num != 0:
print(row_num - 1)
data_list = [] # 定义列表用来存放数据
num = 0 # 用来控制每次插入的数量
for i in range(1, row_num): # 第一行是标题名,对应表中的字段名所以应该从第二行开始,计算机以0开始计数,所以值是1
row_data = sh.row_values(i) # 按行获取excel的值
value = (
row_data[0], row_data[1], row_data[2], row_data[3], row_data[4], row_data[5], row_data[6], row_data[7],
row_data[8])
sql = "INSERT INTO " + str(table_name) + "(brand,sub_model_name,v8_10,`year`,trans_code,oe_code,std_name," \
"`level`,specification,creator,updator) VALUES(%s,%s,%s,%s,%s," \
"%s,%s,%s,%s,\"xing.liuxing1218\",\"xing.liuxing1218\") "
data_list.append(value) # 将数据暂存在列表
num += 1
if num >= 1000: # 每一千条数据执行一次插入
cursor.executemany(sql, data_list) # 执行sql语句
data_list.clear() # 清空list
print("worksheets: " + sheet + " has been inserted 1000 data!")
num = 0 # 计数归零
cursor.executemany(sql, data_list) # 执行sql语句
data_list.clear() # 清空list
print("worksheets: " + sheet + " has been inserted " + str(num) + " data!")
if row_num != 0:
print("Success: worksheets: " + sheet + " has been inserted " + str(row_num - 1) + " data!")
db.commit() # 提交
cursor.close() # 关闭连接
db.close()
return 0


if __name__ == '__main__':
store_to('xxx', 'xxx', 'xxx.xls')

python 复制文件

<返回目录>

1
shutil.copy(src, dst)

python 字符串处理

<返回目录>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 将变量转化成字符串类型
str(line)

# 将字符串全大写/全小写
name = name.upper()
name = name.lower()

# 类 C 语言中的字符串格式化语言,python 中用 % 处理变量转化
ftp_name = "%s_%s"%(xx_id, sec[1])

# strip()去掉字符串首位多余字符,为空时去掉多余空格
# split()将字符串通过参数中的字符,分割成若干字符串存在数组中
plist = pic_advantage.strip().split(",")

# re模块处理正则表达式,以下为将 code 转化为[^a-zA-Z0-9]字符的函数
pattern_code_trim = re.compile("[^a-zA-Z0-9]")
src_code_trim = pattern_code_trim.sub('', code)

# python中没有自增
i = i + 1

python 字典的遍历

<返回目录>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# keys() 该方法会返回字典的所有的key
# 该方法会返回一个序列,序列中保存有字典的所有的键
d = {'name':'孙悟空','age':18,'gender':'男'}
print(d.keys())
# 通过遍历keys()来获取所有的键
for k in d.keys() :
print(k , d[k])

# values()
# 该方法会返回一个序列,序列中保存有字典的所有的值
d = {'name':'孙悟空','age':18,'gender':'男'}
for v in d.values():
print(v)

# items()
# 该方法会返回字典中所有的项
# 它会返回一个序列,序列中包含有双值子序列
# 双值分别是,字典中的key和value
d = {'name':'孙悟空','age':18,'gender':'男'}
print(d.items())
for k,v in d.items():
print(k, '=', v)

python解析json字符串

<返回目录>

1
2
3
4
5
6
7
8
d = json.loads(req.text)
print(d['element'])
print(d['element_parent']['element_child'])

for item in d.items():
print(item[1])
if item[1]['element1'] == 'xx':
print item[1]['element2']

python常用的去重方式

<返回目录>

对列表去重

**1.**用循环查找的方式

1
2
3
4
5
6
li = [1,2,3,3,4,2,3,4,5,6,1]
news_li = []
for i in li:
if i not in news_li:
news_li.append(i)
print (news_li)

**2.**用集合的特性set()

1
2
li1 = [1,4,3,3,4,2,3,4,5,6,1]
new_li1 = list(set(li1))

**3.**使用itertools模块的grouby方法

1
2
3
4
5
6
import itertools
li2 = [1,4,3,3,4,2,3,4,5,6,1]
li2.sort() # 排序
it = itertools.groupby(li2)
for k, g in it:
print (k)

**4.**运用while循环遍历的方式

1
2
3
4
5
6
7
def quchong(lb):
for x in lb:
while lb.count(x)>1:
del lb[lb.index(x)]
return lb
li3 = [1,4,3,3,4,2,3,4,5,6,1]
quchong(li3)

**5.**使用keys()方式

1
2
3
li4 = [1,0,3,7,7,5]
formatli = list({}.fromkeys(li4).keys())
print (formatli)

对数据框去重

**1.**用unique()对单属性列去重

1
2
3
4
5
6
7
import pandas as pd
data = {'id':['A','B','C','C','C','A','B','C','A'],'age':[18,20,14,10,50,14,65,14,98]}
data = pd.DataFrame(data)
data.id.unique()
#或者
import numpy as np
np.unique(data.id)

**2.**用frame.drop_duplicates()对单属性列去重

1
data.drop_duplicates(['id'])

**3.**用frame.drop_duplicates()对多属性列去重

1
data.drop_duplicates(['id','age'])

**4.**用frame.duplicated()对多属性列去重

1
2
isduplicated = data.duplicated(['id','age'],keep='first')
data.loc[~isduplicated,:]

python 查找列表中重复元素以及重复元素的次数

<返回目录>

1
2
3
4
5
6
7
8
from collections import Counter

a = [1, 2, 3, 4, 3, 2, "奔奔", "benben", "奔奔"]
b = dict(Counter(a))
# 只展示重复元素
print ([key for key,value in b.items() if value > 1])
# 展现重复元素和重复次数
print ({key:value for key,value in b.items()if value > 1})

方法一:

1
2
3
4
mylist = [1,2,2,2,2,3,3,3,4,4,4,4]
myset = set(mylist)
for item in myset:
print("the %d has found %d" %(item,mylist.count(item)))
1
2
3
4
the 1 has found 1
the 2 has found 4
the 3 has found 3
the 4 has found 4

方法二:

1
2
3
from collections import Counter

Counter([1,2,2,2,2,3,3,3,4,4,4,4])
1
Counter({2: 4, 4: 4, 3: 3, 1: 1})

方法三:

1
2
3
4
5
6
List=[1,2,2,2,2,3,3,3,4,4,4,4]
a = {}
for i in List:
if List.count(i) > 1:
a[i] = List.count(i)
print (a)

python print 格式化输出

<返回目录>

动态指定长度的实现

1
2
3
4
5
# print %s固定长度格式输出:
print("%10s, %20s" % (A, B))

# 如果长度不定,以变量len代替:
print("%*s" % (len, A))

以指定宽度格式化输出(format)

1
2
3
4
5
mat = "{:20}\t{:28}\t{:32}"
print(mat.format("占4个长度","占8个长度", "占12长度"))
# 如果需要居中输出在宽度前面加一个^
mat = "{:^20}\t{:^28}\t{:^32}"
print(mat.format("占4个长度","占8个长度", "占12长度"))

python Set(集合)相关函数操作

<返回目录>
pythonset和其他语言类似, 是一个无序不重复元素集。基本功能包括关系测试和消除重复元素。集合对象还支持union(联合), intersection(交), difference(差)sysmmetric difference(对称差集)等数学运算。

set 支持 x in set, len(set), 和 for x in set。作为一个无序的集合,set不记录元素位置或者插入点。因此,set不支持 indexing, slicing, 或其它类序列sequence-like的操作。

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
s = set()

len(s)
# set 的长度

x in s
# 测试 x 是否是 s 的成员

x not in s
# 测试 x 是否不是 s 的成员

s.issubset(t) s <= t
# 测试是否 s 中的每一个元素都在 t 中

s.issuperset(t) s >= t
# 测试是否 t 中的每一个元素都在 s 中

s.union(t) s | t
# 返回一个新的 set 包含 s 和 t 中的每一个元素

s.intersection(t) s & t
# 返回一个新的 set 包含 s 和 t 中的公共元素

s.difference(t) s - t
# 返回一个新的 set 包含 s 中有但是 t 中没有的元素

s.symmetric_difference(t) s ^ t
# 返回一个新的 set 包含 s 和 t 中不重复的元素

s.copy()
# 返回 set “s”的一个浅复制

hash(s)
# 返回 s 的 hash 值

s.update(t)
s |= t
# 返回增加了 set “t”中元素后的 set “s”

s.intersection_update(t)
s &= t
# 返回只保留含有 set “t”中元素的 set “s”

s.difference_update(t)
s -= t
# 返回删除了 set “t”中含有的元素后的 set “s”

s.symmetric_difference_update(t)
s ^= t
# 返回含有 set “t”或者 set “s”中有而不是两者都有的元素的 set “s”

s.add(x)
# 向 set “s”中增加元素 x

s.remove(x)
# 从 set “s”中删除元素 x, 如果不存在则引发 KeyError

s.discard(x)
# 如果在 set “s”中存在元素 x, 则删除

s.pop()
# 删除并且返回 set “s”中的一个不确定的元素, 如果为空则引发 KeyError

s.clear()
# 删除 set “s”中的所有元素

Markdown 技能分享

<返回目录>
Markdown是一种轻量级的「标记语言」

Markdown是一种可以使用普通文本编辑器编写的标记语言,通过简单的标记语法,它可以使普通文本内容具有一定的格式。它允许人们使用易读易写的纯文本格式编写文档,然后转换成格式丰富的HTML页面,Markdown文件的后缀名便是“.md”

Markdown增强版中比较有名的有Markdown Extra、MultiMarkdown、 Maruku等。这些衍生版本要么基于工具,如Pandoc,Pandao;要么基于网站,如GitHub和Wikipedia,在语法上基本兼容,但在一些语法和渲染效果上有改动。

Pandao editor.md

Markdown的功能列表演示

1
# 标题H1

标题H1

1
## 标题H2

标题H2

1
### 标题H3

标题H3

1
#### 标题H4

标题H4

1
##### 标题H5
标题H5
1
###### 标题H6
标题H6

字符效果和横线等

1
----

1
~~删除线~~ <s>删除线(开启识别HTML标签时)</s>

删除线 删除线(开启识别HTML标签时)

1
*斜体字*      _斜体字_

斜体字 斜体字

1
**粗体**  __粗体__

粗体 粗体

1
***粗斜体*** ___粗斜体___

粗斜体 粗斜体

1
上标:X<sub>2</sub>,下标:O<sup>2</sup>

上标:X2,下标:O2

缩写(同HTML的abbr标签)

即更长的单词或短语的缩写形式,前提是开启识别HTML标签时,已默认开启

1
The <abbr title="Hyper Text Markup Language">HTML</abbr> specification is maintained by the <abbr title="World Wide Web Consortium">W3C</abbr>.

The HTML specification is maintained by the W3C.

引用 Blockquotes

1
> 引用文本 Blockquotes

引用文本 Blockquotes

引用的行内混合 Blockquotes

1
> 引用:如果想要插入空白换行`即<br />标签`,在插入处先键入两个以上的空格然后回车即可,[普通链接](https://www.mdeditor.com/)。

引用:如果想要插入空白换行即<br />标签,在插入处先键入两个以上的空格然后回车即可,普通链接

1
2
3
4
5
6
7
8
9
[普通链接](https://www.mdeditor.com/)
[普通链接带标题](https://www.mdeditor.com/ "普通链接带标题")
直接链接:<https://www.mdeditor.com>
[锚点链接][anchor-id]
[anchor-id]: https://www.mdeditor.com/
[mailto:test.test@gmail.com](mailto:test.test@gmail.com)
GFM a-tail link @pandao
邮箱地址自动链接 test.test@gmail.com www@vip.qq.com
> @pandao

普通链接
普通链接带标题
直接链接:https://www.mdeditor.com
[锚点链接][anchor-id]
[anchor-id]: https://www.mdeditor.com/
mailto:test.test@gmail.com
GFM a-tail link @pandao
邮箱地址自动链接 test.test@gmail.com www@vip.qq.com

@pandao

多语言代码高亮 Codes

行内代码 Inline code

1
执行命令:`npm install marked`

执行命令:npm install marked

缩进风格

即缩进四个空格,也做为实现类似 <pre> 预格式化文本 ( Preformatted Text ) 的功能。

<?php
    echo "Hello world!";
?>

预格式化文本:

| First Header  | Second Header |
| ------------- | ------------- |
| Content Cell  | Content Cell  |
| Content Cell  | Content Cell  |

JS代码

1
2
3
function test() {
console.log("Hello world!");
}

HTML 代码 HTML codes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html>
<head>
<mate charest="utf-8" />
<meta name="keywords" content="Editor.md, Markdown, Editor" />
<title>Hello world!</title>
<style type="text/css">
body{font-size:14px;color:#444;font-family: "Microsoft Yahei", Tahoma, "Hiragino Sans GB", Arial;background:#fff;}
ul{list-style: none;}
img{border:none;vertical-align: middle;}
</style>
</head>
<body>
<h1 class="text-xxl">Hello world!</h1>
<p class="text-green">Plain text</p>
</body>
</html>

图片 Images

图片加链接 (Image + Link):

Follow your heart.


列表 Lists

无序列表(减号)Unordered Lists (-)

  • 列表一
  • 列表二
  • 列表三

无序列表(星号)Unordered Lists (*)

  • 列表一
  • 列表二
  • 列表三

无序列表(加号和嵌套)Unordered Lists (+)

  • 列表一
  • 列表二
    • 列表二-1
    • 列表二-2
    • 列表二-3
  • 列表三
    • 列表一
    • 列表二
    • 列表三

有序列表 Ordered Lists (-)

  1. 第一行
  2. 第二行
  3. 第三行

GFM task list

  • GFM task list 1
  • GFM task list 2
  • GFM task list 3
    • GFM task list 3-1
    • GFM task list 3-2
    • GFM task list 3-3
  • GFM task list 4
    • GFM task list 4-1
    • GFM task list 4-2

绘制表格 Tables

项目 价格 数量
计算机 $1600 5
手机 $12 12
管线 $1 234
First Header Second Header
Content Cell Content Cell
Content Cell Content Cell
First Header Second Header
Content Cell Content Cell
Content Cell Content Cell
Function name Description
help() Display the help window.
destroy() Destroy your computer!
Left-Aligned Center Aligned Right Aligned
col 3 is some wordy text $1600
col 2 is centered $12
zebra stripes are neat $1
Item Value
Computer $1600
Phone $12
Pipe $1

特殊符号 HTML Entities Codes

1
2
3
4
5
6
7
8
9
&copy; &  &uml; &trade; &iexcl; &pound;

&amp; &lt; &gt; &yen; &euro; &reg;

&plusmn; &para; &sect; &brvbar; &macr; &laquo; &middot;

X&sup2; Y&sup3; &frac34; &frac14; &times; &divide; &raquo;

18&ordm;C &quot; &apos;

&copy; & &uml; &trade; &iexcl; &pound;

& < > &yen; &euro; &reg;

&plusmn; &para; &sect; &brvbar; &macr; &laquo; &middot;

X&sup2; Y&sup3; &frac34; &frac14; &times; &divide; &raquo;

18&ordm;C " &apos;


Emoji表情 :smiley:

Blockquotes :star:

GFM task lists & Emoji & fontAwesome icon emoji & editormd logo emoji :editormd-logo-5x:

  • :smiley: @mentions, :smiley: #refs, links, formatting, and tags supported :editormd-logo:;
  • list syntax required (any unordered or ordered list supported) :editormd-logo-3x:;
  • [ ] :smiley: this is a complete item :smiley:;
  • []this is an incomplete item test link :fa-star: @pandao;
  • [ ]this is an incomplete item :fa-star: :fa-gear:;
    • :smiley: this is an incomplete item test link :fa-star: :fa-gear:;
    • :smiley: this is :fa-star: :fa-gear: an incomplete item test link;

反斜杠 Escape

*literal asterisks*


科学公式 TeX(KaTeX)

$$E=mc^2$$

行内的公式$$E=mc^2$$行内的公式,行内的$$E=mc^2$$公式。

$$x > y$$

$$(\sqrt{3x-1}+(1+x)^2)$$

$$\sin(\alpha)^{\theta}=\sum_{i=0}^{n}(x^i + \cos(f))$$

多行公式:

1
2
3
4
5
\displaystyle
\left( \sum\_{k=1}^n a\_k b\_k \right)^2
\leq
\left( \sum\_{k=1}^n a\_k^2 \right)
\left( \sum\_{k=1}^n b\_k^2 \right)
1
2
3
4
5
6
7
8
9
\displaystyle
\frac{1}{
\Bigl(\sqrt{\phi \sqrt{5}}-\phi\Bigr) e^{
\frac25 \pi}} = 1+\frac{e^{-2\pi}} {1+\frac{e^{-4\pi}} {
1+\frac{e^{-6\pi}}
{1+\frac{e^{-8\pi}}
{1+\cdots} }
}
}
1
2
3
f(x) = \int_{-\infty}^\infty
\hat f(\xi)\,e^{2 \pi i \xi x}
\,d\xi

分页符 Page break

Print Test: Ctrl + P


绘制流程图 Flowchart

1
2
3
4
5
6
7
8
st=>start: 用户登陆
op=>operation: 登陆操作
cond=>condition: 登陆成功 Yes or No?
e=>end: 进入后台

st->op->cond
cond(yes)->e
cond(no)->op

绘制序列图 Sequence Diagram

1
2
3
4
Andrew->China: Says Hello
Note right of China: China thinks\nabout it
China-->Andrew: How are you?
Andrew->>China: I am good thanks!

End

git

<返回目录>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# git 免重复输入密码
git config --global credential.helper store

# zsh gi 模块,自动生产.gitignore 文件
gi python > .gitignore

# git 从本地连接远端仓库(非 git clone 下来的代码)
git remote add origin <url>
git pull --rebase origin master
git push -u origin master

# git 强制拉取最新代码
git fetch --all
git reset --hard origin/<develop>
git pull

git 撤销命令详解

<返回目录>

修改最后一次commit的内容

文件修改后git add了,也git commit了,发现哪里错了或者是漏add了一个文件,可以先git add file后,再git commit –amend这样只会记录一次commit(相当于将两次commit合并成了一次commit)。

取消加入暂存区的文件

不小心用了git add .将所有文件加入了暂存区或者是add多了文件,可以使用git reset HEAD <file>将文件拉回到已修改但是未提交到暂存区的状态。(在add后,通过git status可以看到相应提示,教你如何撤销提交)

取消对当前目录下文件的修改

不小心将文件改崩了,或者发现文件根本没必要修改,可以用git checkout — <file>取消工作区的文件的修改。(同样的,在修改文件后,通过git status可以看到相应提示)

reset 命令的3种模式

git reset –option <commitid>是回滚命令,option 有三个参数可选:

  1. git reset –mixed,这也是默认方式(即不带参数默认是这种),回退暂存区和版本库信息,工作区的源码不会变化,可以重新add,重新commit。
  2. git reset –soft,回退版本库信息,暂存区和工作区都不会变化,如果还要提交,直接commit即可。
  3. git reset –hard,彻底回退,3个区都回退到历史某个版本。

回滚某个文件

  1. git log –pretty=oneline <file>可以查看某个文件的修改历史。
  2. git show commit_id <file>可以查看对应某个commit时期file的内容。
  3. git reset commit_id <file>可以将file回退到某个版本
  4. 执行完第3步后提示:
    1
    2
    Unstaged changes after reset:
    M README.md

执行git status,提示:

1
2
3
4
5
6
7
8
9
10
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

modified: README.md

Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)

modified: README.md

执行git checkout — <file>后,README.md成功回滚到指定版本。

git 去掉多余的commit

<返回目录>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
git rebase -i <commit_ID>
git rebase -i master
git rebase -i HEAD~<num>

// squash:将这一行的 commit 与上一个 commit 进行合并
// fixup:与 squash 相同,只是不会保留这行 commit 的提交 message 信息

// 修改上一次 commit 提交的 message
git commit --amend
// 不过只能修正上一次的 commit。如果很多个 commit 之前就有 message 写错,就得用上我们之前说的 git rebase 了

// 自动标记这一次的 commit 为上一个 commit 的 fix
git commit --fixup <commit>
// 自动组织合并两个 commit
git rebase -i --autosquash

// 撤销过去的 commit 重建一个新的
git reset HEAD~2
git add .
git commit -am "This is the new feature"
git push --force

git commit 技巧

<返回目录>

1
2
3
4
5
6
git commit -s -m  
// 在git log 的时候会多展示 signed-off-by 行

git commit -a -m
// 用于提交跟踪过的文件 ;会自动把修改的文件,先暂存,然后直接commit
// 相当于git add . 与git commit –m “本次提交描述”两句操作合并为一句进行使用。

linux/Unix

<返回目录>

访问本机接口

<返回目录>

1
2
3
curl --location --request POST 'http://本机IP/接口' --header 'Content-Type: application/x-www-form-urlencoded' --data-urlencode 'data=[{"type":1,"brand":"GE","ae_oe_code":"9261317"}]'

curl --location --request GET 'http://127.0.0.1:18016/honda/oe_by_std_name?vin=LVHRM1836D5019492&std_name=%E6%B3%A2%E7%AE%B1%E6%B2%B9'

查看 log 技巧

<返回目录>

1
2
3
4
tail -f <file> i//自动刷新查看文件,适用于查看日志,相对于cat的优点在于不用全部打开,只会看最新的几行,看大文件时不会那么容易卡死

//查看nginx日志,并进行过滤
tail -f /var/log/nginx/access.log | grep XXX

vim 常用快捷键

<返回目录>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ 
// 光标移动到最后一个字符

0
// 光标移动到首位

ZZ
// 保存退出

dt<character>
// 删除到该字符

f<character>
// 将光标移动到,从光标当前位置开始第一个该字符的位置

homebrew

<返回目录>

brew 相关命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
更新:brew update
查看版本:brew -v
帮助信息:brew -h

查询软件的详细信息:brew info <软件名>
查看安装列表:brew list

安装软件包:brew install <软件名>
卸载软件包:brew uninstall <软件名>
彻底卸载指定软件,包括旧版本:brew uninstall --force <软件名>

搜索软件:brew search <正则表达式/软件名>
更新所有软件包:brew upgrade <软件名>
查询有更新版本的软件:brew outdated
清理指定软件的过时包:brew cleanup <软件名>
清理所有的过时软件:brew cleanup
列出需要清理的内容:brew cleanup -n

用浏览器打开相关包的页面:brew home <软件名>
显示包依赖:brew deps <软件名>
锁定某个包:brew pin $FORMULA
取消锁定:brew unpin $FORMULA
查看已安装的包的依赖,树形显示:brew deps --installed --tree

brew 应用包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
tree
// 显示目录层级关系

youtube-dl
// 下载youtube视频

ncdu
// 查看磁盘占用情况

ffmpeg
// 音视频格式转换转码

you-get
// 下载爬取视频

thefuck
// 自动重输正确的建议命令

oh-my-zsh

<返回目录>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
git
// git 快捷指令 由↓查看快捷指令
// cat ~/.oh-my-zsh/plugins/git/git.plugin.zsh

gitignore
// 自动生成gitignore文件
// gi <c/c++/python/...> > .gitignore

zsh_reload
// src 重载zsh

git-open
// 在任何一个git目录,输入git-open 就可以打开github对应的页面

safe-paste
// 当你往 zsh 粘贴脚本时,它不会被立刻运行

extract
// 万能解压命令

gh-md-toc
// md目录生成工具,alias -> mdtoc