-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathstring.ts
204 lines (181 loc) · 4.99 KB
/
string.ts
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
import { is_undefined } from './undefined'
/**
* String.hashCode from Java
* @see [stackoverflow:generate-a-hash-from-string-in-javascript](https://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript)
* @param value string
*/
export function hash_string(value: string): number {
let hash = 0
if (value.length === 0) return hash
for (let i = 0, len = value.length; i < len; i++) {
let chr = value.charCodeAt(i)
hash = (hash << 5) - hash + chr
hash |= 0
}
return hash
}
/**
* Generate random string by `Math.random`
*
* @param length string length
* @throws length greate then 11 or less then 1
*/
export function random_string(length: number = 6): string {
if(length > 11 || length < 1) throw new Error(`length should less then 12 and greater then 0`)
return Math.random().toString(36).substr(2, length)
}
/**
* test value is string type
* @param value value
*/
export function is_string(value: any): value is string {
return 'string' === typeof value || '[object String]' === toString.call(value)
}
/**
* Test string is blank
*
* @param string string
* @param trim should trim string
*/
export function is_blank_string(string: string, trim: boolean = false): string is '' {
if(trim) return '' === string.trim()
return '' === string
}
/**
* Assert string is blank string
*
* @param str string
* @param trim should trim string
* @throws string is blank string
*/
export function assert_non_blank_string(str: string, trim: boolean = false): void {
if(is_blank_string(str, trim)) throw new Error('string is blank string')
}
export const enum PairPattern {
SingleQuotes = "''",
DoubleQuotes = '""',
BackQuotes = '``',
Parenthesis = '()',
SquareBrackets = '[]',
Braces = '{}',
AngleBrackets = '<>',
Underscores = '__',
Stars = '**'
}
const DEFAULT_PAIRS: string[] = [
PairPattern.SingleQuotes,
PairPattern.DoubleQuotes,
PairPattern.BackQuotes,
PairPattern.Parenthesis,
PairPattern.SquareBrackets,
PairPattern.Braces,
PairPattern.AngleBrackets,
PairPattern.Underscores,
PairPattern.Stars
]
/**
* unwrap a string with pair patterns
* @param str string
* @param options unwrapOptions
*/
export function unwrap(str: string, { defaultPairs = true, include = [], exclude = [] }: unwrapOptions = {}): string {
if(is_blank_string(str)) return str
const len: number = str.length
if(1 === len) return str
const fst: string = str.charAt(0)
const lst: string = str.charAt(len - 1)
const join: string = fst + lst
const defaults: string[] = defaultPairs ? DEFAULT_PAIRS : []
const pairs = defaults.concat(include).filter(pair => !exclude.includes(pair))
if(!pairs.includes(join)) return str
return str.substring(1, len - 1)
}
/**
* unwrap deep
* @param str string
* @param options unwrapOptions
*/
export function unwrap_deep(str: string, options: unwrapOptions = {}) {
let prev: string = str
let curr: string
while((curr = unwrap(prev, options))) {
if(curr === prev) return prev
prev = curr
}
return curr
}
/**
* unquote word
* @param str string
* @param options options pass to isBlankString
*/
export function unquote(str: string): string {
return unwrap(str, {
defaultPairs: false,
include: [
PairPattern.SingleQuotes,
PairPattern.DoubleQuotes,
PairPattern.BackQuotes
]
})
}
/**
* unwrap options
*/
interface unwrapOptions {
/**
* not use default pairs
*/
readonly defaultPairs?: boolean
/**
* exclude some pairs
*/
readonly exclude?: ReadonlyArray<string>
/**
* include some pairs
*/
readonly include?: ReadonlyArray<string>
}
/**
* wrap a string by pairs pattern
* @param str string
* @param pairs join pairs
*/
export function wrap_pattern(str: string, pairs: PairPattern | string | [ string, string ]): string {
const [ left, right ]: string[] = is_string(pairs) ? pairs.split('') : pairs
if(is_undefined(left)) return str
return left + str + (is_undefined(right) ? left : right)
}
type Quote =
| PairPattern.SingleQuotes
| PairPattern.DoubleQuotes
| PairPattern.BackQuotes
/**
* wrap string with quote
* @param str string
* @param quote wrap quote, default to Pair.DoubleQuotes
*/
export function wrap_quote(str: string, quote: Quote = PairPattern.DoubleQuotes): string {
return wrap_pattern(str, quote)
}
/**
* wrap string with tag and attributes
* @param str string
* @param tag xml tag
* @param attrs attribute object
*/
export function wrap_xml(str: string, tag: string = 'div', attrs?: { [key: string]: string }): string {
const attrStr: string = (is_blank_string(tag) || is_undefined(attrs)) ? '' : stringify_attrs(attrs)
const tags: [ string, string ] = [`<${tag}${attrStr}>`, `</${tag}>`]
return wrap_pattern(str, tags)
function stringify_attrs(attrs: { [key: string]: string }) {
const acc: string[] = []
for (const key in attrs) {
if (attrs.hasOwnProperty(key)) {
const value = attrs[key]
acc.push(`${key}=${wrap_quote(value)}`)
}
}
return ' ' + acc.join(' ')
}
}