podman

Форк
0
262 строки · 6.2 Кб
1
// Copyright 2015 go-swagger maintainers
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//    http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
package swag
16

17
import (
18
	"unicode"
19
)
20

21
var nameReplaceTable = map[rune]string{
22
	'@': "At ",
23
	'&': "And ",
24
	'|': "Pipe ",
25
	'$': "Dollar ",
26
	'!': "Bang ",
27
	'-': "",
28
	'_': "",
29
}
30

31
type (
32
	splitter struct {
33
		postSplitInitialismCheck bool
34
		initialisms              []string
35
	}
36

37
	splitterOption func(*splitter) *splitter
38
)
39

40
// split calls the splitter; splitter provides more control and post options
41
func split(str string) []string {
42
	lexems := newSplitter().split(str)
43
	result := make([]string, 0, len(lexems))
44

45
	for _, lexem := range lexems {
46
		result = append(result, lexem.GetOriginal())
47
	}
48

49
	return result
50

51
}
52

53
func (s *splitter) split(str string) []nameLexem {
54
	return s.toNameLexems(str)
55
}
56

57
func newSplitter(options ...splitterOption) *splitter {
58
	splitter := &splitter{
59
		postSplitInitialismCheck: false,
60
		initialisms:              initialisms,
61
	}
62

63
	for _, option := range options {
64
		splitter = option(splitter)
65
	}
66

67
	return splitter
68
}
69

70
// withPostSplitInitialismCheck allows to catch initialisms after main split process
71
func withPostSplitInitialismCheck(s *splitter) *splitter {
72
	s.postSplitInitialismCheck = true
73
	return s
74
}
75

76
type (
77
	initialismMatch struct {
78
		start, end int
79
		body       []rune
80
		complete   bool
81
	}
82
	initialismMatches []*initialismMatch
83
)
84

85
func (s *splitter) toNameLexems(name string) []nameLexem {
86
	nameRunes := []rune(name)
87
	matches := s.gatherInitialismMatches(nameRunes)
88
	return s.mapMatchesToNameLexems(nameRunes, matches)
89
}
90

91
func (s *splitter) gatherInitialismMatches(nameRunes []rune) initialismMatches {
92
	matches := make(initialismMatches, 0)
93

94
	for currentRunePosition, currentRune := range nameRunes {
95
		newMatches := make(initialismMatches, 0, len(matches))
96

97
		// check current initialism matches
98
		for _, match := range matches {
99
			if keepCompleteMatch := match.complete; keepCompleteMatch {
100
				newMatches = append(newMatches, match)
101
				continue
102
			}
103

104
			// drop failed match
105
			currentMatchRune := match.body[currentRunePosition-match.start]
106
			if !s.initialismRuneEqual(currentMatchRune, currentRune) {
107
				continue
108
			}
109

110
			// try to complete ongoing match
111
			if currentRunePosition-match.start == len(match.body)-1 {
112
				// we are close; the next step is to check the symbol ahead
113
				// if it is a small letter, then it is not the end of match
114
				// but beginning of the next word
115

116
				if currentRunePosition < len(nameRunes)-1 {
117
					nextRune := nameRunes[currentRunePosition+1]
118
					if newWord := unicode.IsLower(nextRune); newWord {
119
						// oh ok, it was the start of a new word
120
						continue
121
					}
122
				}
123

124
				match.complete = true
125
				match.end = currentRunePosition
126
			}
127

128
			newMatches = append(newMatches, match)
129
		}
130

131
		// check for new initialism matches
132
		for _, initialism := range s.initialisms {
133
			initialismRunes := []rune(initialism)
134
			if s.initialismRuneEqual(initialismRunes[0], currentRune) {
135
				newMatches = append(newMatches, &initialismMatch{
136
					start:    currentRunePosition,
137
					body:     initialismRunes,
138
					complete: false,
139
				})
140
			}
141
		}
142

143
		matches = newMatches
144
	}
145

146
	return matches
147
}
148

149
func (s *splitter) mapMatchesToNameLexems(nameRunes []rune, matches initialismMatches) []nameLexem {
150
	nameLexems := make([]nameLexem, 0)
151

152
	var lastAcceptedMatch *initialismMatch
153
	for _, match := range matches {
154
		if !match.complete {
155
			continue
156
		}
157

158
		if firstMatch := lastAcceptedMatch == nil; firstMatch {
159
			nameLexems = append(nameLexems, s.breakCasualString(nameRunes[:match.start])...)
160
			nameLexems = append(nameLexems, s.breakInitialism(string(match.body)))
161

162
			lastAcceptedMatch = match
163

164
			continue
165
		}
166

167
		if overlappedMatch := match.start <= lastAcceptedMatch.end; overlappedMatch {
168
			continue
169
		}
170

171
		middle := nameRunes[lastAcceptedMatch.end+1 : match.start]
172
		nameLexems = append(nameLexems, s.breakCasualString(middle)...)
173
		nameLexems = append(nameLexems, s.breakInitialism(string(match.body)))
174

175
		lastAcceptedMatch = match
176
	}
177

178
	// we have not found any accepted matches
179
	if lastAcceptedMatch == nil {
180
		return s.breakCasualString(nameRunes)
181
	}
182

183
	if lastAcceptedMatch.end+1 != len(nameRunes) {
184
		rest := nameRunes[lastAcceptedMatch.end+1:]
185
		nameLexems = append(nameLexems, s.breakCasualString(rest)...)
186
	}
187

188
	return nameLexems
189
}
190

191
func (s *splitter) initialismRuneEqual(a, b rune) bool {
192
	return a == b
193
}
194

195
func (s *splitter) breakInitialism(original string) nameLexem {
196
	return newInitialismNameLexem(original, original)
197
}
198

199
func (s *splitter) breakCasualString(str []rune) []nameLexem {
200
	segments := make([]nameLexem, 0)
201
	currentSegment := ""
202

203
	addCasualNameLexem := func(original string) {
204
		segments = append(segments, newCasualNameLexem(original))
205
	}
206

207
	addInitialismNameLexem := func(original, match string) {
208
		segments = append(segments, newInitialismNameLexem(original, match))
209
	}
210

211
	addNameLexem := func(original string) {
212
		if s.postSplitInitialismCheck {
213
			for _, initialism := range s.initialisms {
214
				if upper(initialism) == upper(original) {
215
					addInitialismNameLexem(original, initialism)
216
					return
217
				}
218
			}
219
		}
220

221
		addCasualNameLexem(original)
222
	}
223

224
	for _, rn := range string(str) {
225
		if replace, found := nameReplaceTable[rn]; found {
226
			if currentSegment != "" {
227
				addNameLexem(currentSegment)
228
				currentSegment = ""
229
			}
230

231
			if replace != "" {
232
				addNameLexem(replace)
233
			}
234

235
			continue
236
		}
237

238
		if !unicode.In(rn, unicode.L, unicode.M, unicode.N, unicode.Pc) {
239
			if currentSegment != "" {
240
				addNameLexem(currentSegment)
241
				currentSegment = ""
242
			}
243

244
			continue
245
		}
246

247
		if unicode.IsUpper(rn) {
248
			if currentSegment != "" {
249
				addNameLexem(currentSegment)
250
			}
251
			currentSegment = ""
252
		}
253

254
		currentSegment += string(rn)
255
	}
256

257
	if currentSegment != "" {
258
		addNameLexem(currentSegment)
259
	}
260

261
	return segments
262
}
263

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.