react-util-tools 1.0.25 → 1.0.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -0
- package/dist/index.cjs +317 -0
- package/dist/index.d.cts +45 -1
- package/dist/index.d.ts +45 -1
- package/dist/index.js +274 -0
- package/package.json +1 -1
- package/src/index.ts +45 -0
- package/src/string/README.md +441 -0
- package/src/string/index.ts +527 -0
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 字符串工具函数
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 首字母大写
|
|
7
|
+
* @param str 字符串
|
|
8
|
+
* @returns 首字母大写的字符串
|
|
9
|
+
*/
|
|
10
|
+
export function capitalize(str: string): string {
|
|
11
|
+
if (!str) return ''
|
|
12
|
+
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase()
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 驼峰命名转换(首字母小写)
|
|
17
|
+
* @param str 字符串
|
|
18
|
+
* @returns 驼峰命名字符串
|
|
19
|
+
*/
|
|
20
|
+
export function camelCase(str: string): string {
|
|
21
|
+
if (!str) return ''
|
|
22
|
+
return str
|
|
23
|
+
.replace(/[-_\s]+(.)?/g, (_, char) => (char ? char.toUpperCase() : ''))
|
|
24
|
+
.replace(/^[A-Z]/, char => char.toLowerCase())
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 帕斯卡命名转换(首字母大写)
|
|
29
|
+
* @param str 字符串
|
|
30
|
+
* @returns 帕斯卡命名字符串
|
|
31
|
+
*/
|
|
32
|
+
export function pascalCase(str: string): string {
|
|
33
|
+
if (!str) return ''
|
|
34
|
+
const camel = camelCase(str)
|
|
35
|
+
return camel.charAt(0).toUpperCase() + camel.slice(1)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 蛇形命名转换(下划线分隔)
|
|
40
|
+
* @param str 字符串
|
|
41
|
+
* @returns 蛇形命名字符串
|
|
42
|
+
*/
|
|
43
|
+
export function snakeCase(str: string): string {
|
|
44
|
+
if (!str) return ''
|
|
45
|
+
return str
|
|
46
|
+
.replace(/([A-Z])/g, '_$1')
|
|
47
|
+
.replace(/[-\s]+/g, '_')
|
|
48
|
+
.replace(/^_/, '')
|
|
49
|
+
.toLowerCase()
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 短横线命名转换(kebab-case)
|
|
54
|
+
* @param str 字符串
|
|
55
|
+
* @returns 短横线命名字符串
|
|
56
|
+
*/
|
|
57
|
+
export function kebabCase(str: string): string {
|
|
58
|
+
if (!str) return ''
|
|
59
|
+
return str
|
|
60
|
+
.replace(/([A-Z])/g, '-$1')
|
|
61
|
+
.replace(/[_\s]+/g, '-')
|
|
62
|
+
.replace(/^-/, '')
|
|
63
|
+
.toLowerCase()
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* 截断字符串
|
|
68
|
+
* @param str 字符串
|
|
69
|
+
* @param length 最大长度
|
|
70
|
+
* @param suffix 后缀,默认 '...'
|
|
71
|
+
* @returns 截断后的字符串
|
|
72
|
+
*/
|
|
73
|
+
export function truncate(str: string, length: number, suffix = '...'): string {
|
|
74
|
+
if (!str || str.length <= length) return str
|
|
75
|
+
return str.slice(0, length) + suffix
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 移除字符串两端空格
|
|
80
|
+
* @param str 字符串
|
|
81
|
+
* @returns 移除空格后的字符串
|
|
82
|
+
*/
|
|
83
|
+
export function trim(str: string): string {
|
|
84
|
+
return str ? str.trim() : ''
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* 移除字符串左侧空格
|
|
89
|
+
* @param str 字符串
|
|
90
|
+
* @returns 移除空格后的字符串
|
|
91
|
+
*/
|
|
92
|
+
export function trimStart(str: string): string {
|
|
93
|
+
return str ? str.trimStart() : ''
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 移除字符串右侧空格
|
|
98
|
+
* @param str 字符串
|
|
99
|
+
* @returns 移除空格后的字符串
|
|
100
|
+
*/
|
|
101
|
+
export function trimEnd(str: string): string {
|
|
102
|
+
return str ? str.trimEnd() : ''
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* 反转字符串
|
|
107
|
+
* @param str 字符串
|
|
108
|
+
* @returns 反转后的字符串
|
|
109
|
+
*/
|
|
110
|
+
export function reverse(str: string): string {
|
|
111
|
+
if (!str) return ''
|
|
112
|
+
return str.split('').reverse().join('')
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* 重复字符串
|
|
117
|
+
* @param str 字符串
|
|
118
|
+
* @param count 重复次数
|
|
119
|
+
* @returns 重复后的字符串
|
|
120
|
+
*/
|
|
121
|
+
export function repeat(str: string, count: number): string {
|
|
122
|
+
if (!str || count <= 0) return ''
|
|
123
|
+
return str.repeat(count)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* 填充字符串(左侧)
|
|
128
|
+
* @param str 字符串
|
|
129
|
+
* @param length 目标长度
|
|
130
|
+
* @param padStr 填充字符,默认空格
|
|
131
|
+
* @returns 填充后的字符串
|
|
132
|
+
*/
|
|
133
|
+
export function padStart(str: string, length: number, padStr = ' '): string {
|
|
134
|
+
if (!str) return padStr.repeat(length)
|
|
135
|
+
return str.padStart(length, padStr)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* 填充字符串(右侧)
|
|
140
|
+
* @param str 字符串
|
|
141
|
+
* @param length 目标长度
|
|
142
|
+
* @param padStr 填充字符,默认空格
|
|
143
|
+
* @returns 填充后的字符串
|
|
144
|
+
*/
|
|
145
|
+
export function padEnd(str: string, length: number, padStr = ' '): string {
|
|
146
|
+
if (!str) return padStr.repeat(length)
|
|
147
|
+
return str.padEnd(length, padStr)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* 判断字符串是否以指定字符串开头
|
|
152
|
+
* @param str 字符串
|
|
153
|
+
* @param searchString 搜索字符串
|
|
154
|
+
* @returns 是否以指定字符串开头
|
|
155
|
+
*/
|
|
156
|
+
export function startsWith(str: string, searchString: string): boolean {
|
|
157
|
+
if (!str) return false
|
|
158
|
+
return str.startsWith(searchString)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* 判断字符串是否以指定字符串结尾
|
|
163
|
+
* @param str 字符串
|
|
164
|
+
* @param searchString 搜索字符串
|
|
165
|
+
* @returns 是否以指定字符串结尾
|
|
166
|
+
*/
|
|
167
|
+
export function endsWith(str: string, searchString: string): boolean {
|
|
168
|
+
if (!str) return false
|
|
169
|
+
return str.endsWith(searchString)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* 判断字符串是否包含指定字符串
|
|
174
|
+
* @param str 字符串
|
|
175
|
+
* @param searchString 搜索字符串
|
|
176
|
+
* @returns 是否包含指定字符串
|
|
177
|
+
*/
|
|
178
|
+
export function includes(str: string, searchString: string): boolean {
|
|
179
|
+
if (!str) return false
|
|
180
|
+
return str.includes(searchString)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* 替换字符串中的所有匹配项
|
|
185
|
+
* @param str 字符串
|
|
186
|
+
* @param search 搜索字符串或正则表达式
|
|
187
|
+
* @param replacement 替换字符串
|
|
188
|
+
* @returns 替换后的字符串
|
|
189
|
+
*/
|
|
190
|
+
export function replaceAll(
|
|
191
|
+
str: string,
|
|
192
|
+
search: string | RegExp,
|
|
193
|
+
replacement: string
|
|
194
|
+
): string {
|
|
195
|
+
if (!str) return ''
|
|
196
|
+
if (typeof search === 'string') {
|
|
197
|
+
return str.split(search).join(replacement)
|
|
198
|
+
}
|
|
199
|
+
return str.replace(search, replacement)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* 移除字符串中的 HTML 标签
|
|
204
|
+
* @param str 字符串
|
|
205
|
+
* @returns 移除 HTML 标签后的字符串
|
|
206
|
+
*/
|
|
207
|
+
export function stripHtml(str: string): string {
|
|
208
|
+
if (!str) return ''
|
|
209
|
+
return str.replace(/<[^>]*>/g, '')
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* 转义 HTML 特殊字符
|
|
214
|
+
* @param str 字符串
|
|
215
|
+
* @returns 转义后的字符串
|
|
216
|
+
*/
|
|
217
|
+
export function escapeHtml(str: string): string {
|
|
218
|
+
if (!str) return ''
|
|
219
|
+
const map: Record<string, string> = {
|
|
220
|
+
'&': '&',
|
|
221
|
+
'<': '<',
|
|
222
|
+
'>': '>',
|
|
223
|
+
'"': '"',
|
|
224
|
+
"'": '''
|
|
225
|
+
}
|
|
226
|
+
return str.replace(/[&<>"']/g, char => map[char])
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* 反转义 HTML 特殊字符
|
|
231
|
+
* @param str 字符串
|
|
232
|
+
* @returns 反转义后的字符串
|
|
233
|
+
*/
|
|
234
|
+
export function unescapeHtml(str: string): string {
|
|
235
|
+
if (!str) return ''
|
|
236
|
+
const map: Record<string, string> = {
|
|
237
|
+
'&': '&',
|
|
238
|
+
'<': '<',
|
|
239
|
+
'>': '>',
|
|
240
|
+
'"': '"',
|
|
241
|
+
''': "'"
|
|
242
|
+
}
|
|
243
|
+
return str.replace(/&(amp|lt|gt|quot|#39);/g, entity => map[entity])
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* 转换为小写
|
|
248
|
+
* @param str 字符串
|
|
249
|
+
* @returns 小写字符串
|
|
250
|
+
*/
|
|
251
|
+
export function toLowerCase(str: string): string {
|
|
252
|
+
return str ? str.toLowerCase() : ''
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* 转换为大写
|
|
257
|
+
* @param str 字符串
|
|
258
|
+
* @returns 大写字符串
|
|
259
|
+
*/
|
|
260
|
+
export function toUpperCase(str: string): string {
|
|
261
|
+
return str ? str.toUpperCase() : ''
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* 单词首字母大写
|
|
266
|
+
* @param str 字符串
|
|
267
|
+
* @returns 单词首字母大写的字符串
|
|
268
|
+
*/
|
|
269
|
+
export function titleCase(str: string): string {
|
|
270
|
+
if (!str) return ''
|
|
271
|
+
return str
|
|
272
|
+
.toLowerCase()
|
|
273
|
+
.split(' ')
|
|
274
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
275
|
+
.join(' ')
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* 判断是否为空字符串(包括只有空格的字符串)
|
|
280
|
+
* @param str 字符串
|
|
281
|
+
* @returns 是否为空
|
|
282
|
+
*/
|
|
283
|
+
export function isEmpty(str: string): boolean {
|
|
284
|
+
return !str || str.trim().length === 0
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* 判断是否不为空字符串
|
|
289
|
+
* @param str 字符串
|
|
290
|
+
* @returns 是否不为空
|
|
291
|
+
*/
|
|
292
|
+
export function isNotEmpty(str: string): boolean {
|
|
293
|
+
return !isEmpty(str)
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* 获取字符串长度(支持 Unicode)
|
|
298
|
+
* @param str 字符串
|
|
299
|
+
* @returns 字符串长度
|
|
300
|
+
*/
|
|
301
|
+
export function length(str: string): number {
|
|
302
|
+
if (!str) return 0
|
|
303
|
+
return Array.from(str).length
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* 分割字符串为数组
|
|
308
|
+
* @param str 字符串
|
|
309
|
+
* @param separator 分隔符
|
|
310
|
+
* @returns 字符串数组
|
|
311
|
+
*/
|
|
312
|
+
export function split(str: string, separator: string | RegExp): string[] {
|
|
313
|
+
if (!str) return []
|
|
314
|
+
return str.split(separator)
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* 提取数字
|
|
319
|
+
* @param str 字符串
|
|
320
|
+
* @returns 数字数组
|
|
321
|
+
*/
|
|
322
|
+
export function extractNumbers(str: string): number[] {
|
|
323
|
+
if (!str) return []
|
|
324
|
+
const matches = str.match(/\d+(\.\d+)?/g)
|
|
325
|
+
return matches ? matches.map(Number) : []
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* 移除所有空格
|
|
330
|
+
* @param str 字符串
|
|
331
|
+
* @returns 移除空格后的字符串
|
|
332
|
+
*/
|
|
333
|
+
export function removeSpaces(str: string): string {
|
|
334
|
+
if (!str) return ''
|
|
335
|
+
return str.replace(/\s+/g, '')
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* 移除多余空格(保留单个空格)
|
|
340
|
+
* @param str 字符串
|
|
341
|
+
* @returns 移除多余空格后的字符串
|
|
342
|
+
*/
|
|
343
|
+
export function normalizeSpaces(str: string): string {
|
|
344
|
+
if (!str) return ''
|
|
345
|
+
return str.replace(/\s+/g, ' ').trim()
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* 计算字符串中某个子串出现的次数
|
|
350
|
+
* @param str 字符串
|
|
351
|
+
* @param searchString 搜索字符串
|
|
352
|
+
* @returns 出现次数
|
|
353
|
+
*/
|
|
354
|
+
export function countOccurrences(str: string, searchString: string): number {
|
|
355
|
+
if (!str || !searchString) return 0
|
|
356
|
+
return str.split(searchString).length - 1
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* 随机字符串生成
|
|
361
|
+
* @param length 长度
|
|
362
|
+
* @param chars 字符集,默认包含字母和数字
|
|
363
|
+
* @returns 随机字符串
|
|
364
|
+
*/
|
|
365
|
+
export function randomString(
|
|
366
|
+
length: number,
|
|
367
|
+
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
|
368
|
+
): string {
|
|
369
|
+
let result = ''
|
|
370
|
+
for (let i = 0; i < length; i++) {
|
|
371
|
+
result += chars.charAt(Math.floor(Math.random() * chars.length))
|
|
372
|
+
}
|
|
373
|
+
return result
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* 生成 UUID v4
|
|
378
|
+
* @returns UUID 字符串
|
|
379
|
+
*/
|
|
380
|
+
export function uuid(): string {
|
|
381
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
|
|
382
|
+
const r = (Math.random() * 16) | 0
|
|
383
|
+
const v = c === 'x' ? r : (r & 0x3) | 0x8
|
|
384
|
+
return v.toString(16)
|
|
385
|
+
})
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* 手机号脱敏
|
|
390
|
+
* @param phone 手机号
|
|
391
|
+
* @returns 脱敏后的手机号
|
|
392
|
+
*/
|
|
393
|
+
export function maskPhone(phone: string): string {
|
|
394
|
+
if (!phone || phone.length < 11) return phone
|
|
395
|
+
return phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2')
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* 身份证号脱敏
|
|
400
|
+
* @param idCard 身份证号
|
|
401
|
+
* @returns 脱敏后的身份证号
|
|
402
|
+
*/
|
|
403
|
+
export function maskIdCard(idCard: string): string {
|
|
404
|
+
if (!idCard || idCard.length < 18) return idCard
|
|
405
|
+
return idCard.replace(/(\d{6})\d{8}(\d{4})/, '$1********$2')
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* 银行卡号脱敏
|
|
410
|
+
* @param cardNumber 银行卡号
|
|
411
|
+
* @returns 脱敏后的银行卡号
|
|
412
|
+
*/
|
|
413
|
+
export function maskBankCard(cardNumber: string): string {
|
|
414
|
+
if (!cardNumber || cardNumber.length < 16) return cardNumber
|
|
415
|
+
return cardNumber.replace(/(\d{4})\d+(\d{4})/, '$1 **** **** $2')
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* 姓名脱敏
|
|
420
|
+
* @param name 姓名
|
|
421
|
+
* @returns 脱敏后的姓名
|
|
422
|
+
*/
|
|
423
|
+
export function maskName(name: string): string {
|
|
424
|
+
if (!name) return ''
|
|
425
|
+
if (name.length === 2) {
|
|
426
|
+
return name.charAt(0) + '*'
|
|
427
|
+
}
|
|
428
|
+
return name.charAt(0) + '*'.repeat(name.length - 2) + name.charAt(name.length - 1)
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* 判断是否为有效的手机号(中国大陆)
|
|
433
|
+
* @param phone 手机号
|
|
434
|
+
* @returns 是否有效
|
|
435
|
+
*/
|
|
436
|
+
export function isValidPhone(phone: string): boolean {
|
|
437
|
+
if (!phone) return false
|
|
438
|
+
return /^1[3-9]\d{9}$/.test(phone)
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* 判断是否为有效的邮箱
|
|
443
|
+
* @param email 邮箱
|
|
444
|
+
* @returns 是否有效
|
|
445
|
+
*/
|
|
446
|
+
export function isValidEmail(email: string): boolean {
|
|
447
|
+
if (!email) return false
|
|
448
|
+
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* 判断是否为有效的 URL
|
|
453
|
+
* @param url URL
|
|
454
|
+
* @returns 是否有效
|
|
455
|
+
*/
|
|
456
|
+
export function isValidUrl(url: string): boolean {
|
|
457
|
+
if (!url) return false
|
|
458
|
+
try {
|
|
459
|
+
new URL(url)
|
|
460
|
+
return true
|
|
461
|
+
} catch {
|
|
462
|
+
return false
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* 判断是否为有效的身份证号(中国大陆)
|
|
468
|
+
* @param idCard 身份证号
|
|
469
|
+
* @returns 是否有效
|
|
470
|
+
*/
|
|
471
|
+
export function isValidIdCard(idCard: string): boolean {
|
|
472
|
+
if (!idCard) return false
|
|
473
|
+
return /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(idCard)
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* 字符串转 Base64
|
|
478
|
+
* @param str 字符串
|
|
479
|
+
* @returns Base64 字符串
|
|
480
|
+
*/
|
|
481
|
+
export function toBase64(str: string): string {
|
|
482
|
+
if (!str) return ''
|
|
483
|
+
if (typeof window !== 'undefined' && window.btoa) {
|
|
484
|
+
try {
|
|
485
|
+
return window.btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (_, p1) => {
|
|
486
|
+
return String.fromCharCode(parseInt(p1, 16))
|
|
487
|
+
}))
|
|
488
|
+
} catch {
|
|
489
|
+
return ''
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
// Node.js 环境
|
|
493
|
+
try {
|
|
494
|
+
const BufferClass = (globalThis as any).Buffer
|
|
495
|
+
return BufferClass ? BufferClass.from(str, 'utf-8').toString('base64') : ''
|
|
496
|
+
} catch {
|
|
497
|
+
return ''
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Base64 转字符串
|
|
503
|
+
* @param base64 Base64 字符串
|
|
504
|
+
* @returns 原始字符串
|
|
505
|
+
*/
|
|
506
|
+
export function fromBase64(base64: string): string {
|
|
507
|
+
if (!base64) return ''
|
|
508
|
+
if (typeof window !== 'undefined' && window.atob) {
|
|
509
|
+
try {
|
|
510
|
+
const binary = window.atob(base64)
|
|
511
|
+
const bytes = new Uint8Array(binary.length)
|
|
512
|
+
for (let i = 0; i < binary.length; i++) {
|
|
513
|
+
bytes[i] = binary.charCodeAt(i)
|
|
514
|
+
}
|
|
515
|
+
return new TextDecoder().decode(bytes)
|
|
516
|
+
} catch {
|
|
517
|
+
return ''
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
// Node.js 环境
|
|
521
|
+
try {
|
|
522
|
+
const BufferClass = (globalThis as any).Buffer
|
|
523
|
+
return BufferClass ? BufferClass.from(base64, 'base64').toString('utf-8') : ''
|
|
524
|
+
} catch {
|
|
525
|
+
return ''
|
|
526
|
+
}
|
|
527
|
+
}
|