Skip to content

Commit

Permalink
feat: 添加数据脱敏 (MrXujiang#44)
Browse files Browse the repository at this point in the history
* docs: 修改(prettier/prettier) 报错

* docs: update README.md

* docs: update no-console 报 error

* docs: update no-constant-condition 报 error

* docs: update no-constant-condition 报 error

* docs: 添加 IPv6 正则表达式

* docs: 添加 IPv6 正则表达式

* docs: delete no-console

* docs: dele ipv6

* feat: 添加数据脱敏

* feat: 添加数据脱敏

* feat: 添加数据脱敏

* feat: 添加 双向链表
wujixialan authored Apr 30, 2023
1 parent 7ca5e1f commit e660768
Showing 8 changed files with 337 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -49,6 +49,7 @@
- isIdCard - 判断身份证格式函数
- lang - 判断中英文
- regexp - 常用正则表达式
- dataDesensitization - 数据脱敏
- 数据结构相关
- cloneDeep - 数据深拷贝
- arrayToListNode - 数组转成链表
@@ -62,6 +63,7 @@
- obj2url - 将对象参数解析为url字符串
- transformTree - 扁平转树结构
- url2obj - url字符串转对象
- bothLinkedList - 双向链表
- 图片处理函数
- compressImg - 自定义压缩图片函数
- file2img - 文件转图片对象
44 changes: 44 additions & 0 deletions src/BothLinkedList/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
title: bothLinkedList - 双向链表
nav:
title: 使用文档
path: /lib
group:
path: /format
title: 数据结构相关
order: 2
---

## bothLinkedList

> 双向链表
>
> bothLinkedList.insertHead(param): param 是 需要插入的元素,插入到元素链表尾部 <br>
> bothLinkedList.insertIndex(param, index): param 是 需要插入的元素,index: 需要插入的位置 <br>
> bothLinkedList.getHead(): 从头开始遍历链表 <br>
> bothLinkedList.getTail(): 从尾开始遍历链表 <br>
> bothLinkedList.getData(index): index: 通过索引获取元素值 <br>
> bothLinkedList.getSize(): 获取链表长度 <br>
> bothLinkedList.deleteFrom(index): index 通过索引删除元素节点 <br>
> bothLinkedList.deleteData(param): index 通过元素值删除元素节点 <br>
>
> 返回值:Node 类型:
>
> { data: 1, next: undefined, prev: undefined }
Demo:

```tsx | pure
import { BothLinkedList } from 'xijs';

let bothLinkedList = new BothLinkedList()
bothLinkedList.insertHead(1);
bothLinkedList.insertHead(2);
// bothLinkedList.insertHead(3)
console.log(bothLinkedList.getHead())
bothLinkedList.deleteFrom(1)
bothLinkedList.deleteData(1)
console.log(bothLinkedList.getHead())
// console.log(bothLinkedList.getTail())
// console.log(bothLinkedList.getData(3))
```
175 changes: 175 additions & 0 deletions src/BothLinkedList/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
/**
* 定义链表结构
* @param data
* @param next
* @constructor
*/
class Node<T> {
data: T;
next: Node<T> | undefined;
prev: Node<T> | undefined;

constructor(data: T) {
this.data = data;
}
}
class BothLinkedList<T> {
private head: Node<T> | undefined;
private tail: Node<T> | undefined;
private size = 0;

/**
* 插入元素 采用尾插法
* @param data
*/
insertHead(data: T): void {
const node = new Node(data);
if (this.size === 0) {
this.head = node;
this.tail = node;
} else {
node.prev = this.tail;
this.tail!.next = node;
this.tail = node;
}
this.size++;
}

/**
* 根据索引插入元素
* @param data
* @param index
*/
insertIndex(data: T, index: number): void {
if (index < 0 || index > this.size) {
throw new Error("要插入的索引已经超过了链表的最大长度");
}
const node = new Node(data);
/**
* 如果链表为空,直接插入
*/
if (this.head === null) {
this.head = node;
this.tail = node;
}
/**
* 如果 index === 0 则插入的位置是头
* 如果 index === this.size 则插入的位置是尾
*/
if (index === 0) {
node.next = this.head;
this.head!.prev = node;
this.head = node;
} else if (index === this.size) {
node.prev = this.tail;
this.tail!.next = node;
this.tail = node;
} else {
let current = this.head!;
for (let i = 0; i < index - 1; i++) {
current = current.next!;
}
node.prev = current;
node.next = current.next;
current.next!.prev = node;
current.next = node;
}
this.size++;
}

/**
* 删除元素(根据元素值进行删除)
*/
deleteData(data: string): void {
if (this.size === 0) {
throw Error("双向链表为空,不能删除")
}
let current = this.head!;
while (current) {
if (current.data === data) {
if (this.size === 1) {
this.head = undefined;
this.tail = undefined;
} else if (current === this.head) {
this.head = this.head!.next;
this.head!.prev = undefined;
} else if (current === this.tail) {
this.tail = this.tail!.prev;
this.tail!.next = undefined;
} else {
current.prev!.next = current.next;
current.next!.prev = current.prev;
}

this.size--;
return;
}
current = current!.next!;
}
}

/**
* 根据元素索引删除
* @param index
*/
deleteFrom(index: number): void {
if (index < 0 || index >= this.size) {
throw new Error("Index out of range");
}
if (this.size === 1) {
this.head = undefined;
this.tail = undefined;
} else if (index === 0) {
this.head = this.head!.next!;
this.head!.prev = undefined;
} else if (index === this.size - 1) {
this.tail = this.tail!.prev;
this.tail!.next = undefined;
} else {
let current = this.head!;
for (let i = 0; i < index; i++) {
current = current.next!;
}
current.prev!.next = current.next;
current.next!.prev = current.prev;
}
this.size--;
}

/**
* 正向遍历
*/
getHead(): Node<T> | undefined {
return this.head;
}

/**
* 反向遍历
*/
getTail(): Node<T> | undefined {
return this.tail;
}

/**
* 获取链表长度
*/
getSize(): number {
return this.size;
}

/**
* 更具索引,获取元素值
* @param index
*/
getData(index: number): T | undefined {
if (index < 0 || index >= this.size) {
throw Error("要查找的索引已经超过了链表的最大长度")
}
let current = this.head;
for (let i = 0; i < index; i++) {
current = current!.next;
}
return current!.data;
}
}
export default BothLinkedList;
43 changes: 43 additions & 0 deletions src/dataDesensitization/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
title: dataDesensitization - 数据脱敏
nav:
title: 使用文档
path: /lib
group:
path: /judge
title: 常用判断函数
order: 12
---

## dataDesensitization

> 数据脱敏
>
> regex(param1, param2, param3m param4): param1 是 需要脱敏的类型,param2:需要脱敏的数据, param3: 自定义脱敏时 脱敏开始位置, param4: 自定义脱敏的位数
>
> idCard: 身份证 脱敏<br>
> phone: 手机号 脱敏<br>
> fixPhone: 手机号 脱敏<br>
> email: 邮箱 脱敏<br>
> username: 姓名 脱敏<br>
> custom: 自定义 脱敏<br>
>
> 返回值为 string 值,脱敏完的字符串
Demo:

```tsx | pure

// 按需引入
import { dataDesensitization } from 'xijs';

console.log('610222188709080909: ', dataDesensitization('idCard', '610222188709080909'));
console.log('18396781187: ', dataDesensitization('phone', '18396781187'));
console.log('18396781187: ', dataDesensitization('custom', '18396781187', 1, 8));
console.log('深证市龙岗区五和: ', dataDesensitization('address', '深证市龙岗区五和'));
console.log('1832291@qq.com: ', dataDesensitization('email', '1832291@qq.com'));
console.log('小小西: ', dataDesensitization('username', '小小西'));
console.log('小西: ', dataDesensitization('username', '小西'));
console.log('小西小西: ', dataDesensitization('username', '小西小西'));
console.log('012-1823293: ', dataDesensitization('fixPhone', '012-1823293'));
```
45 changes: 45 additions & 0 deletions src/dataDesensitization/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { repeat } from "../index";

const dataDesensitizationMap = {
idCard: (data: string): string => {
return data.replace(/(\d{2})\d{14}(\w{2})/, "$1" + repeat("*", 14) + "$2");
},
phone: (data: string): string => {
return data.replace(/(\d{3})\d{4}(\d{4})/, "$1****$2");
},
bankCard: (data: string): string => {
return data.replace(/(\d{4})\d{10}(\w{4})/, "$1" + repeat("*", 10) + "$2");
},
address: (data: string): string => {
return data.replace(/(\S{2})\S*/, "$1" + repeat("*", data.length - 2));
},
custom: (data: string, begin: number, desensitization: number): string => {
const end = data.length - begin - desensitization;
const regexp = RegExp(`(\\d{` + begin + `})\\d{` + desensitization + `}(\\w{` + end + `})`);
return data.replace(regexp, "$1" + repeat("*", desensitization) + "$2");
},
fixPhone: (data: string): string => {
return data.replace(/(\w{3}-)\w*/, "$1" + repeat("*", data.length - 4));
},
email: (data: string): string => {
return data.replace(/(\w?)(\w+)(\w)(@\w+\.[a-z]+(\.[a-z]+)?)/, '$1****$3$4')
},
username: (data: string): string => {
return data.replace(/(\S)(\S*)/, "$1" + repeat("*", data.length - 1))
}
};

type DataDesensitization = "idCard" | "bankCard" | "phone" | "address" | "custom" | "fixPhone" | "email" | "username";
const dataDesensitization = (des: DataDesensitization, data: string, begin = 0, desensitization = 0) => {
if (des === "custom") {
return dataDesensitizationMap["custom"](data, begin, desensitization);
} else if (dataDesensitizationMap[des]) {
return dataDesensitizationMap[des](data);
} else {
throw Error("请输入正确的脱敏类型");
}
return;
};


export default dataDesensitization;
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -69,3 +69,5 @@ export { default as minBy } from './minBy';
export { default as maxBy } from './maxBy';

export { default as completeIp } from './completeIp';
export { default as dataDesensitization } from './dataDesensitization';
export { default as BothLinkedList } from './BothLinkedList';
13 changes: 13 additions & 0 deletions test/BothLinkedList.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { BothLinkedList } from '../src/index';
describe('双向链表相关测试', () => {
test('双向链表', () => {
const bothLinkedList = new BothLinkedList();
const insertRes = { data: 1, next: undefined, prev: undefined }
bothLinkedList.insertHead(1);
expect(bothLinkedList.getHead()).toEqual(insertRes)
bothLinkedList.insertHead(2);
bothLinkedList.deleteData(2);
bothLinkedList.deleteData(1);
expect(bothLinkedList.getHead()).toEqual(undefined)
});
});
13 changes: 13 additions & 0 deletions test/dataDesensitization.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

import { dataDesensitization, repeat } from '../src/index';
describe('数据脱敏相关测试', () => {
test('数据脱敏', () => {
expect(dataDesensitization('idCard', '610222188709080909')).toEqual('61**************09')
expect(dataDesensitization('phone', '18396781187')).toEqual('183****1187')
expect(dataDesensitization('custom', '18396781187', 1, 8)).toEqual('1********87')
expect(dataDesensitization('address', '深证市龙岗区五和')).toEqual('深证******')
expect(dataDesensitization('email', '1832291@qq.com')).toEqual('1****1@qq.com')
expect(dataDesensitization('username', '小小西')).toEqual('小**')
expect(dataDesensitization('fixPhone', '012-1823293')).toEqual('012-*******')
});
});

0 comments on commit e660768

Please sign in to comment.