pyjallib 0.1.0__py3-none-any.whl

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.
pyjallib/naming.py ADDED
@@ -0,0 +1,1066 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ Naming 모듈 - 이름 규칙 관리 및 적용 기능 제공
6
+ NamePart 객체를 기반으로 조직화된 이름 생성 및 분석 기능 구현
7
+ """
8
+
9
+ import os
10
+ import re
11
+ from dataclasses import dataclass
12
+ from typing import List, Dict, Any, Optional, Union, Tuple
13
+
14
+ # NamePart와 NamingConfig 임포트
15
+ from pyjallib.namePart import NamePart, NamePartType
16
+ from pyjallib.namingConfig import NamingConfig
17
+
18
+ class Naming:
19
+ """
20
+ 노드 이름을 관리하기 위한 기본 클래스.
21
+ 기본적인 이름 구성 요소를 정의하고 관리합니다.
22
+ 이 클래스는 하위 클래스에서 확장하여 특정 목적에 맞게 사용할 수 있습니다.
23
+ """
24
+
25
+ def __init__(self, configPath=None):
26
+ """
27
+ 클래스 초기화 및 기본 설정값 정의
28
+
29
+ Args:
30
+ configPath: 설정 파일 경로 (기본값: None)
31
+ 설정 파일이 제공되면 해당 파일에서 설정을 로드함
32
+ """
33
+ # 기본 설정값
34
+ self._paddingNum = 2
35
+ self._configPath = configPath
36
+
37
+ # 기본 namePart 초기화 (각 부분에 사전 정의 값 직접 설정)
38
+ self._nameParts = []
39
+
40
+ # Prefix 부분 (PREFIX 타입)
41
+ prefixPart = NamePart("Prefix", NamePartType.PREFIX, ["Pr"], ["Prefix"])
42
+
43
+ # RealName 부분 (REALNAME 타입)
44
+ realNamePart = NamePart("RealName", NamePartType.REALNAME, [], [])
45
+
46
+ # Index 부분 (INDEX 타입)
47
+ indexPart = NamePart("Index", NamePartType.INDEX, [], [])
48
+
49
+ # Suffix 부분 (SUFFIX 타입)
50
+ suffixPart = NamePart("Suffix", NamePartType.SUFFIX, ["Su"], ["Suffix"])
51
+
52
+ # 기본 순서대로 설정
53
+ self._nameParts = [prefixPart, realNamePart, indexPart, suffixPart]
54
+
55
+ # 설정 파일이 제공된 경우 로드
56
+ if configPath:
57
+ self.load_from_config_file(configPath)
58
+ else:
59
+ # 기본 JSON 설정 파일 로드 시도
60
+ self.load_default_config()
61
+
62
+ # ---- String 관련 메소드들 (내부 사용 헬퍼 메소드) ----
63
+
64
+ def _split_into_string_and_digit(self, inStr):
65
+ """
66
+ 문자열을 문자부분과 숫자부분으로 분리
67
+
68
+ Args:
69
+ inStr: 분리할 문자열
70
+
71
+ Returns:
72
+ 튜플 (문자부분, 숫자부분)
73
+ """
74
+ match = re.match(r'^(.*?)(\d*)$', inStr)
75
+ if match:
76
+ return match.group(1), match.group(2)
77
+ return inStr, ""
78
+
79
+ def _compare_string(self, inStr1, inStr2):
80
+ """
81
+ 대소문자 구분 없이 문자열 비교
82
+
83
+ Args:
84
+ inStr1: 첫 번째 문자열
85
+ inStr2: 두 번째 문자열
86
+
87
+ Returns:
88
+ 비교 결과 (inStr1 < inStr2: 음수, inStr1 == inStr2: 0, inStr1 > inStr2: 양수)
89
+ """
90
+ # Python에서는 대소문자 구분 없는 비교를 위해 lower() 메서드 사용
91
+ if inStr1.lower() < inStr2.lower():
92
+ return -1
93
+ elif inStr1.lower() > inStr2.lower():
94
+ return 1
95
+ return 0
96
+
97
+ def _sort_by_alphabet(self, inArray):
98
+ """
99
+ 배열 내 문자열을 알파벳 순으로 정렬
100
+
101
+ Args:
102
+ inArray: 정렬할 배열
103
+
104
+ Returns:
105
+ 정렬된 배열
106
+ """
107
+ # Python의 sorted 함수와 lambda를 사용하여 대소문자 구분 없이 정렬
108
+ return sorted(inArray, key=lambda x: x.lower())
109
+
110
+ def _get_filtering_char(self, inStr):
111
+ """
112
+ 문자열에서 사용된 구분자 문자 찾기
113
+
114
+ Args:
115
+ inStr: 확인할 문자열
116
+
117
+ Returns:
118
+ 구분자 문자 (' ' 또는 '_' 또는 '')
119
+ """
120
+ if ' ' in inStr:
121
+ return ' '
122
+ if '_' in inStr:
123
+ return '_'
124
+ return ''
125
+
126
+ def _filter_by_filtering_char(self, inStr):
127
+ """
128
+ 구분자 문자로 문자열 분할
129
+
130
+ Args:
131
+ inStr: 분할할 문자열
132
+
133
+ Returns:
134
+ 분할된 문자열 리스트
135
+ """
136
+ filChar = self._get_filtering_char(inStr)
137
+
138
+ if not filChar:
139
+ return [inStr]
140
+
141
+ # 빈 문자열 제거하며 분할
142
+ return [part for part in inStr.split(filChar) if part]
143
+
144
+ def _filter_by_upper_case(self, inStr):
145
+ """
146
+ 대문자로 시작하는 부분을 기준으로 문자열 분할
147
+
148
+ Args:
149
+ inStr: 분할할 문자열
150
+
151
+ Returns:
152
+ 분할된 문자열 리스트
153
+ """
154
+ if not inStr:
155
+ return []
156
+
157
+ result = []
158
+ currentPart = inStr[0]
159
+
160
+ for i in range(1, len(inStr)):
161
+ if inStr[i].isupper():
162
+ result.append(currentPart)
163
+ currentPart = inStr[i]
164
+ else:
165
+ currentPart += inStr[i]
166
+
167
+ if currentPart:
168
+ result.append(currentPart)
169
+
170
+ return result
171
+
172
+ def _has_digit(self, inStr):
173
+ """
174
+ 문자열에 숫자가 포함되어 있는지 확인
175
+
176
+ Args:
177
+ inStr: 확인할 문자열
178
+
179
+ Returns:
180
+ 숫자가 포함되어 있으면 True, 아니면 False
181
+ """
182
+ return any(char.isdigit() for char in inStr)
183
+
184
+ def _split_to_array(self, inStr):
185
+ """
186
+ 문자열을 구분자 또는 대문자로 분할하고 숫자 부분도 분리
187
+
188
+ Args:
189
+ inStr: 분할할 문자열
190
+
191
+ Returns:
192
+ 분할된 문자열 리스트
193
+ """
194
+ filChar = self._get_filtering_char(inStr)
195
+
196
+ if not filChar:
197
+ # 구분자가 없을 경우 대문자로 분할
198
+ resultArray = self._filter_by_upper_case(inStr)
199
+ tempArray = []
200
+
201
+ for item in resultArray:
202
+ if self._has_digit(item):
203
+ stringPart, digitPart = self._split_into_string_and_digit(item)
204
+ if stringPart:
205
+ tempArray.append(stringPart)
206
+ if digitPart:
207
+ tempArray.append(digitPart)
208
+ else:
209
+ tempArray.append(item)
210
+
211
+ return tempArray
212
+ else:
213
+ # 구분자가 있을 경우 구분자로 분할
214
+ return self._filter_by_filtering_char(inStr)
215
+
216
+ def _remove_empty_string_in_array(self, inArray):
217
+ """
218
+ 배열에서 빈 문자열 제거
219
+
220
+ Args:
221
+ inArray: 처리할 배열
222
+
223
+ Returns:
224
+ 빈 문자열이 제거된 배열
225
+ """
226
+ return [item for item in inArray if item]
227
+
228
+ def _combine(self, inArray, inFilChar=" "):
229
+ """
230
+ 문자열 배열을 하나의 문자열로 결합
231
+
232
+ Args:
233
+ inArray: 결합할 문자열 배열
234
+ filChar: 구분자 (기본값: 공백)
235
+
236
+ Returns:
237
+ 결합된 문자열
238
+ """
239
+ refinedArray = self._remove_empty_string_in_array(inArray)
240
+
241
+ if not refinedArray:
242
+ return ""
243
+
244
+ if len(refinedArray) == 1:
245
+ return refinedArray[0]
246
+
247
+ return inFilChar.join(refinedArray)
248
+
249
+ # ---- Name 관련 메서드들 ----
250
+
251
+ # 사전 정의 값 편집 메서드 제거 (namingConfig를 통해서만 변경 가능)
252
+
253
+ def get_padding_num(self):
254
+ """
255
+ 패딩 숫자 가져오기
256
+
257
+ Returns:
258
+ 패딩 숫자
259
+ """
260
+ return self._paddingNum
261
+
262
+ def get_name_part(self, inNamePartName):
263
+ """
264
+ namePart 이름으로 NamePart 객체 가져오기
265
+
266
+ Args:
267
+ namePart: 가져올 NamePart의 이름 ("Prefix", "RealName", "Suffix", "Index" 등)
268
+
269
+ Returns:
270
+ 해당 NamePart 객체, 존재하지 않으면 None
271
+ """
272
+ for part in self._nameParts:
273
+ if part.get_name() == inNamePartName:
274
+ return part
275
+ return None
276
+
277
+ def get_name_part_index(self, inNamePartName):
278
+ """
279
+ namePart 이름으로 인덱스 가져오기
280
+
281
+ Args:
282
+ namePart: 가져올 NamePart의 이름 ("Prefix", "RealName", "Suffix", "Index" 등)
283
+
284
+ Returns:
285
+ 해당 NamePart의 인덱스, 존재하지 않으면 -1
286
+ """
287
+ for i, part in enumerate(self._nameParts):
288
+ if part.get_name() == inNamePartName:
289
+ return i
290
+ return -1
291
+
292
+ def get_name_part_predefined_values(self, inNamePartName):
293
+ """
294
+ namePart의 사전 정의 값 가져오기
295
+
296
+ Args:
297
+ namePart: 가져올 NamePart의 이름 ("Prefix", "RealName", "Suffix", "Index" 등)
298
+
299
+ Returns:
300
+ 해당 NamePart의 사전 정의 값 리스트, 존재하지 않으면 빈 리스트
301
+ """
302
+ partObj = self.get_name_part(inNamePartName)
303
+ if partObj:
304
+ return partObj.get_predefined_values()
305
+ return []
306
+
307
+ def is_in_name_part_predefined_values(self, inNamePartName, inStr):
308
+ """
309
+ 지정된 namePart에 해당하는 부분이 문자열에 포함되어 있는지 확인
310
+
311
+ Args:
312
+ namePart: 확인할 namePart 이름 ("Base", "Type", "Side" 등)
313
+ inStr: 확인할 문자열
314
+
315
+ Returns:
316
+ 포함되어 있으면 True, 아니면 False
317
+ """
318
+ partObj = self.get_name_part(inNamePartName)
319
+ if not partObj:
320
+ return False
321
+
322
+ partType = partObj.get_type()
323
+ if not partType:
324
+ return False
325
+
326
+ partValues = partObj.get_predefined_values()
327
+
328
+ if partType == NamePartType.PREFIX or partType == NamePartType.SUFFIX:
329
+ return any(item in inStr for item in partValues)
330
+
331
+ return False
332
+
333
+ def get_name_part_value_by_description(self, inNamePartName, inDescription):
334
+ """
335
+ 지정된 namePart에 해당하는 부분을 문자열에서 추출
336
+
337
+ Args:
338
+ namePart: 추출할 namePart 이름 ("Base", "Type", "Side" 등)
339
+ inDescription: predefined value에서 찾기위한 description 문자열
340
+
341
+ Returns:
342
+ 지정된 namePart에 해당하는 문자열
343
+ """
344
+ partObj = self.get_name_part(inNamePartName)
345
+ if not partObj:
346
+ return ""
347
+
348
+ partType = partObj.get_type()
349
+ if not partType:
350
+ return ""
351
+
352
+ partValues = partObj.get_predefined_values()
353
+
354
+ if partType == NamePartType.PREFIX or partType == NamePartType.SUFFIX:
355
+ foundIndex = partObj._descriptions.index(inDescription)
356
+ if foundIndex >= 0:
357
+ return partValues[foundIndex]
358
+
359
+ return ""
360
+
361
+ def pick_name(self, inNamePartName, inStr):
362
+ nameArray = self._split_to_array(inStr)
363
+ returnStr = ""
364
+
365
+ # namePart 문자열 목록 가져오기
366
+ partObj = self.get_name_part(inNamePartName)
367
+ if not partObj:
368
+ return returnStr
369
+
370
+ partType = partObj.get_type()
371
+ if not partType:
372
+ return returnStr
373
+
374
+ partValues = partObj.get_predefined_values()
375
+ if partType != NamePartType.INDEX and partType != NamePartType.REALNAME and not partValues:
376
+ return returnStr
377
+
378
+ if partType == NamePartType.PREFIX:
379
+ for item in nameArray:
380
+ if item in partValues:
381
+ returnStr = item
382
+ break
383
+
384
+ if partType == NamePartType.SUFFIX:
385
+ for i in range(len(nameArray) - 1, -1, -1):
386
+ if nameArray[i] in partValues:
387
+ returnStr = nameArray[i]
388
+ break
389
+
390
+ if partType == NamePartType.INDEX:
391
+ if self.get_name_part_index("Index") > self.get_name_part_index("RealName"):
392
+ for i in range(len(nameArray) - 1, -1, -1):
393
+ if nameArray[i].isdigit():
394
+ returnStr = nameArray[i]
395
+ break
396
+ else:
397
+ for item in nameArray:
398
+ if item.isdigit():
399
+ returnStr = item
400
+ break
401
+
402
+ return returnStr
403
+
404
+ def get_name(self, inNamePartName, inStr):
405
+ """
406
+ 지정된 namePart에 해당하는 부분을 문자열에서 추출
407
+
408
+ Args:
409
+ namePart: 추출할 namePart 이름 ("Base", "Type", "Side" 등)
410
+ inStr: 처리할 문자열
411
+
412
+ Returns:
413
+ 지정된 namePart에 해당하는 문자열
414
+ """
415
+ nameArray = self._split_to_array(inStr)
416
+ returnStr = ""
417
+
418
+ partType = self.get_name_part(inNamePartName).get_type()
419
+
420
+ foundName = self.pick_name(inNamePartName, inStr)
421
+ if foundName == "":
422
+ return returnStr
423
+ partIndex = self.get_name_part_index(inNamePartName)
424
+ foundIndex = nameArray.index(foundName)
425
+
426
+ if partType == NamePartType.PREFIX:
427
+ if foundIndex >= 0:
428
+ prevNameParts = self._nameParts[:partIndex]
429
+ prevNames = [self.pick_name(part.get_name(), inStr) for part in prevNameParts]
430
+ prevNamesInNameArray = nameArray[:foundIndex]
431
+ for prevName in prevNames:
432
+ if prevName in prevNamesInNameArray:
433
+ prevNamesInNameArray.remove(prevName)
434
+ if len(prevNamesInNameArray) == 0 :
435
+ returnStr = foundName
436
+
437
+ if partType == NamePartType.SUFFIX:
438
+ if foundIndex >= 0:
439
+ nextNameParts = self._nameParts[partIndex + 1:]
440
+ nextNames = [self.pick_name(part.get_name(), inStr) for part in nextNameParts]
441
+ nextNamesInNameArray = nameArray[foundIndex + 1:]
442
+ for nextName in nextNames:
443
+ if nextName in nextNamesInNameArray:
444
+ nextNamesInNameArray.remove(nextName)
445
+ if len(nextNamesInNameArray) == 0 :
446
+ returnStr = foundName
447
+
448
+ if partType == NamePartType.INDEX:
449
+ returnStr = self.pick_name(inNamePartName, inStr)
450
+
451
+ return returnStr
452
+
453
+ def combine(self, inPartsDict={}, inFilChar=" "):
454
+ """
455
+ namingConfig에서 정의된 nameParts와 그 순서에 따라 이름 부분들을 조합하여 완전한 이름 생성
456
+
457
+ Args:
458
+ parts_dict: namePart 이름과 값의 딕셔너리 (예: {"Base": "b", "Type": "P", "Side": "L"})
459
+ inFilChar: 구분자 문자 (기본값: " ")
460
+
461
+ Returns:
462
+ 조합된 이름 문자열
463
+ """
464
+ # 결과 배열 초기화 (빈 문자열로)
465
+ combinedNameArray = [""] * len(self._nameParts)
466
+
467
+ # 각 namePart에 대해
468
+ for i, part in enumerate(self._nameParts):
469
+ partName = part.get_name()
470
+ # 딕셔너리에서 해당 부분의 값 가져오기 (없으면 빈 문자열 사용)
471
+ if partName in inPartsDict:
472
+ combinedNameArray[i] = inPartsDict[partName]
473
+
474
+ # 배열을 문자열로 결합
475
+ newName = self._combine(combinedNameArray, inFilChar)
476
+ newName = self.set_index_padding_num(newName)
477
+ return newName
478
+
479
+ def get_RealName(self, inStr):
480
+ """
481
+ 문자열에서 실제 이름 부분 추출
482
+
483
+ Args:
484
+ inStr: 처리할 문자열
485
+
486
+ Returns:
487
+ 실제 이름 부분 문자열
488
+ """
489
+ filChar = self._get_filtering_char(inStr)
490
+ nameArray = self._split_to_array(inStr)
491
+
492
+ # 모든 nameParts 중 RealName이 아닌 것들의 값을 수집
493
+ nonRealNameArray = []
494
+ for part in self._nameParts:
495
+ partName = part.get_name()
496
+ partType = part.get_type()
497
+ if partType != NamePartType.REALNAME:
498
+ foundName = self.get_name(partName, inStr)
499
+ nonRealNameArray.append(foundName)
500
+
501
+ for item in nonRealNameArray:
502
+ if item in nameArray:
503
+ nameArray.remove(item)
504
+
505
+ # 구분자로 결합
506
+ return self._combine(nameArray, filChar)
507
+
508
+ def get_non_RealName(self, inStr):
509
+ """
510
+ 실제 이름 부분을 제외한 이름 가져오기
511
+
512
+ Args:
513
+ inStr: 처리할 이름 문자열
514
+
515
+ Returns:
516
+ 실제 이름이 제외된 이름 문자열
517
+ """
518
+ filChar = self._get_filtering_char(inStr)
519
+
520
+ # 모든 nameParts 중 RealName이 아닌 것들의 값을 수집
521
+ nonRealNameArray = []
522
+ for part in self._nameParts:
523
+ partName = part.get_name()
524
+ partType = part.get_type()
525
+ if partType != NamePartType.REALNAME:
526
+ foundName = self.get_name(partName, inStr)
527
+ nonRealNameArray.append(foundName)
528
+
529
+ return self._combine(nonRealNameArray, filChar)
530
+
531
+ def convert_name_to_array(self, inStr):
532
+ """
533
+ 문자열 이름을 이름 부분 배열로 변환
534
+
535
+ Args:
536
+ inStr: 변환할 이름 문자열
537
+
538
+ Returns:
539
+ 이름 부분 배열 (Base, Type, Side, FrontBack, RealName, Index, Nub 등)
540
+ """
541
+ returnArray = [""] * len(self._nameParts)
542
+
543
+ # 각 namePart에 대해 처리
544
+ for i, part in enumerate(self._nameParts):
545
+ partName = part.get_name()
546
+
547
+ # 특수 케이스인 RealName은 마지막에 처리하기 위해 저장
548
+ if partName == "RealName":
549
+ realNameIndex = i
550
+ continue
551
+
552
+ # get_name 메소드를 사용하여 해당 부분 추출
553
+ partValue = self.get_name(partName, inStr)
554
+ returnArray[i] = partValue
555
+
556
+ # 마지막으로 RealName 처리 (다른 모든 부분을 찾은 후에 수행해야 함)
557
+ if 'realNameIndex' in locals():
558
+ realNameStr = self.get_RealName(inStr)
559
+ returnArray[realNameIndex] = realNameStr
560
+
561
+ return returnArray
562
+
563
+ def convert_to_dictionary(self, inStr):
564
+ """
565
+ 문자열 이름을 이름 부분 딕셔너리로 변환
566
+
567
+ Args:
568
+ inStr: 변환할 이름 문자열
569
+
570
+ Returns:
571
+ 이름 부분 딕셔너리 (키: namePart 이름, 값: 추출된 값)
572
+ 예: {"Base": "b", "Type": "P", "Side": "L", "RealName": "Arm", ...}
573
+ """
574
+ returnDict = {}
575
+
576
+ # 각 namePart에 대해 처리
577
+ for part in self._nameParts:
578
+ partName = part.get_name()
579
+
580
+ # 특수 케이스인 RealName은 마지막에 처리하기 위해 저장
581
+ if partName == "RealName":
582
+ continue
583
+
584
+ # get_name 메소드를 사용하여 해당 부분 추출
585
+ partValue = self.get_name(partName, inStr)
586
+ returnDict[partName] = partValue
587
+
588
+ # 마지막으로 RealName 처리 (다른 모든 부분을 찾은 후에 수행해야 함)
589
+ realNameStr = self.get_RealName(inStr)
590
+ returnDict["RealName"] = realNameStr
591
+
592
+ return returnDict
593
+
594
+ def convert_to_description(self, inStr):
595
+ """
596
+ 문자열 이름을 설명으로 변환
597
+
598
+ Args:
599
+ inStr: 변환할 이름 문자열
600
+
601
+ Returns:
602
+ 설명 문자열 (예: "b_P_L_Arm")
603
+ """
604
+ nameDic = self.convert_to_dictionary(inStr)
605
+ descriptionDic = {}
606
+ filteringChar = self._get_filtering_char(inStr)
607
+ descName = inStr
608
+ if nameDic:
609
+ for namePartName, value in nameDic.items():
610
+ namePart = self.get_name_part(namePartName)
611
+ desc = namePart.get_description_by_value(value)
612
+
613
+ if desc == "" and value != "":
614
+ desc = value
615
+
616
+ descriptionDic[namePartName] = desc # Store in dictionary for later use
617
+
618
+ descName = self.combine(descriptionDic, filteringChar)
619
+
620
+ return descName
621
+
622
+ def convert_to_korean_description(self, inStr):
623
+ """
624
+ 문자열 이름을 한국어 설명으로 변환
625
+
626
+ Args:
627
+ inStr: 변환할 이름 문자열
628
+
629
+ Returns:
630
+ 한국어 설명 문자열 (예: "팔_왼쪽_팔")
631
+ """
632
+ nameDic = self.convert_to_dictionary(inStr)
633
+ korDescDic = {}
634
+ filteringChar = self._get_filtering_char(inStr)
635
+ korDescName = inStr
636
+ if nameDic:
637
+ for namePartName, value in nameDic.items():
638
+ namePart = self.get_name_part(namePartName)
639
+ desc = namePart.get_description_by_value(value)
640
+ korDesc = namePart.get_korean_description_by_value(value)
641
+
642
+ if korDesc == "" and desc != "":
643
+ korDesc = desc
644
+
645
+ korDescDic[namePartName] = korDesc # Store in dictionary for later use
646
+
647
+ korDescName = self.combine(korDescDic, filteringChar)
648
+
649
+ return korDescName
650
+
651
+ def has_name_part(self, inPart, inStr):
652
+ """
653
+ 문자열에 특정 namePart가 포함되어 있는지 확인
654
+
655
+ Args:
656
+ inPart: 확인할 namePart 이름 ("Base", "Type", "Side", "FrontBack", "RealName", "Index")
657
+ inStr: 확인할 문자열
658
+
659
+ Returns:
660
+ 포함되어 있으면 True, 아니면 False
661
+ """
662
+ return self.get_name(inPart, inStr) != ""
663
+
664
+ def add_prefix_to_name_part(self, inPart, inStr, inPrefix):
665
+ """
666
+ 이름의 특정 부분에 접두사 추가
667
+
668
+ Args:
669
+ inPart: 수정할 부분 ("Base", "Type", "Side", "FrontBack", "RealName", "Index")
670
+ inStr: 처리할 이름 문자열
671
+ inPrefix: 추가할 접두사
672
+
673
+ Returns:
674
+ 수정된 이름 문자열
675
+ """
676
+ returnStr = inStr
677
+
678
+ if inPrefix:
679
+ filChar = self._get_filtering_char(inStr)
680
+ nameArray = self.convert_name_to_array(inStr)
681
+ partIndex = self.get_name_part_index(inPart)
682
+
683
+ nameArray[partIndex] = inPrefix + nameArray[partIndex]
684
+
685
+ returnStr = self._combine(nameArray, filChar)
686
+
687
+ return returnStr
688
+
689
+ def add_suffix_to_name_part(self, inPart, inStr, inSuffix):
690
+ """
691
+ 이름의 특정 부분에 접미사 추가
692
+
693
+ Args:
694
+ inPart: 수정할 부분 ("Base", "Type", "Side", "FrontBack", "RealName", "Index")
695
+ inStr: 처리할 이름 문자열
696
+ inSuffix: 추가할 접미사
697
+
698
+ Returns:
699
+ 수정된 이름 문자열
700
+ """
701
+ returnStr = inStr
702
+
703
+ if inSuffix:
704
+ filChar = self._get_filtering_char(inStr)
705
+ nameArray = self.convert_name_to_array(inStr)
706
+ partIndex = self.get_name_part_index(inPart)
707
+
708
+ nameArray[partIndex] = nameArray[partIndex] + inSuffix
709
+
710
+ returnStr = self._combine(nameArray, filChar)
711
+
712
+ return returnStr
713
+
714
+ def add_prefix_to_real_name(self, inStr, inPrefix):
715
+ """
716
+ 실제 이름 부분에 접두사 추가
717
+
718
+ Args:
719
+ inStr: 처리할 이름 문자열
720
+ inPrefix: 추가할 접두사
721
+
722
+ Returns:
723
+ 수정된 이름 문자열
724
+ """
725
+ return self.add_prefix_to_name_part("RealName", inStr, inPrefix)
726
+
727
+ def add_suffix_to_real_name(self, inStr, inSuffix):
728
+ """
729
+ 실제 이름 부분에 접미사 추가
730
+
731
+ Args:
732
+ inStr: 처리할 이름 문자열
733
+ inSuffix: 추가할 접미사
734
+
735
+ Returns:
736
+ 수정된 이름 문자열
737
+ """
738
+ return self.add_suffix_to_name_part("RealName", inStr, inSuffix)
739
+
740
+ def convert_digit_into_padding_string(self, inDigit, inPaddingNum=None):
741
+ """
742
+ 숫자를 패딩된 문자열로 변환
743
+
744
+ Args:
745
+ inDigit: 변환할 숫자 또는 숫자 문자열
746
+ inPaddingNum: 패딩 자릿수 (기본값: 클래스의 _paddingNum)
747
+
748
+ Returns:
749
+ 패딩된 문자열
750
+ """
751
+ if inPaddingNum is None:
752
+ inPaddingNum = self._paddingNum
753
+
754
+ digitNum = 0
755
+
756
+ if isinstance(inDigit, int):
757
+ digitNum = inDigit
758
+ elif isinstance(inDigit, str):
759
+ if inDigit.isdigit():
760
+ digitNum = int(inDigit)
761
+
762
+ # Python의 문자열 포맷팅을 사용하여 패딩
763
+ return f"{digitNum:0{inPaddingNum}d}"
764
+
765
+ def set_index_padding_num(self, inStr, inPaddingNum=None):
766
+ """
767
+ 이름의 인덱스 부분 패딩 설정
768
+
769
+ Args:
770
+ inStr: 처리할 이름 문자열
771
+ inPaddingNum: 설정할 패딩 자릿수 (기본값: 클래스의 _paddingNum)
772
+
773
+ Returns:
774
+ 패딩이 적용된 이름 문자열
775
+ """
776
+ if inPaddingNum is None:
777
+ inPaddingNum = self._paddingNum
778
+
779
+ filChar = self._get_filtering_char(inStr)
780
+ nameArray = self.convert_name_to_array(inStr)
781
+ indexIndex = self.get_name_part_index("Index")
782
+ indexStr = self.get_name("Index", inStr)
783
+
784
+ if indexStr:
785
+ indexStr = self.convert_digit_into_padding_string(indexStr, inPaddingNum)
786
+ nameArray[indexIndex] = indexStr
787
+
788
+ return self._combine(nameArray, filChar)
789
+
790
+ def get_index_padding_num(self, inStr):
791
+ """
792
+ 이름의 인덱스 부분 패딩 자릿수 가져오기
793
+
794
+ Args:
795
+ inStr: 처리할 이름 문자열
796
+
797
+ Returns:
798
+ 인덱스 패딩 자릿수
799
+ """
800
+ indexVal = self.get_name("Index", inStr)
801
+
802
+ if indexVal:
803
+ return len(indexVal)
804
+
805
+ return 1
806
+
807
+ def increase_index(self, inStr, inAmount):
808
+ """
809
+ 이름의 인덱스 부분 값 증가
810
+
811
+ Args:
812
+ inStr: 처리할 이름 문자열
813
+ inAmount: 증가시킬 값
814
+
815
+ Returns:
816
+ 인덱스가 증가된 이름 문자열
817
+ """
818
+ newName = inStr
819
+ filChar = self._get_filtering_char(inStr)
820
+ nameArray = self.convert_name_to_array(inStr)
821
+ indexIndex = self.get_name_part_index("Index")
822
+
823
+ if indexIndex >= 0:
824
+ indexStr = ""
825
+ indexPaddingNum = self._paddingNum
826
+ indexNum = -99999
827
+
828
+ if not nameArray[indexIndex]:
829
+ indexNum = -1
830
+ else:
831
+ try:
832
+ indexNum = int(nameArray[indexIndex])
833
+ indexPaddingNum = len(nameArray[indexIndex])
834
+ except ValueError:
835
+ pass
836
+
837
+ indexNum += inAmount
838
+
839
+ if indexNum < 0:
840
+ indexNum = 0
841
+
842
+ # Python의 문자열 포맷팅을 사용하여 패딩
843
+ indexStr = f"{indexNum:0{indexPaddingNum}d}"
844
+ nameArray[indexIndex] = indexStr
845
+ newName = self._combine(nameArray, filChar)
846
+ newName = self.set_index_padding_num(newName)
847
+
848
+ return newName
849
+
850
+ def get_index_as_digit(self, inStr):
851
+ """
852
+ 이름의 인덱스를 숫자로 변환
853
+
854
+ Args:
855
+ inStr: 변환할 이름 문자열
856
+
857
+ Returns:
858
+ 숫자로 변환된 인덱스 (넙이 있으면 -1, 인덱스가 없으면 False)
859
+ """
860
+ indexStr = self.get_name("Index", inStr)
861
+
862
+ if indexStr:
863
+ try:
864
+ return int(indexStr)
865
+ except ValueError:
866
+ pass
867
+
868
+ return False
869
+
870
+ def sort_by_index(self, inNameArray):
871
+ """
872
+ 이름 배열을 인덱스 기준으로 정렬
873
+
874
+ Args:
875
+ inNameArray: 정렬할 이름 배열
876
+
877
+ Returns:
878
+ 인덱스 기준으로 정렬된 이름 배열
879
+ """
880
+ if not inNameArray:
881
+ return []
882
+
883
+ # 정렬을 위한 보조 클래스 정의
884
+ @dataclass
885
+ class IndexSorting:
886
+ oriIndex: int
887
+ newIndex: int
888
+
889
+ # 각 이름의 인덱스를 추출하여 정렬 정보 생성
890
+ structArray = []
891
+
892
+ for i, name in enumerate(inNameArray):
893
+ tempIndex = self.get_index_as_digit(name)
894
+
895
+ if tempIndex is False:
896
+ structArray.append(IndexSorting(i, 0))
897
+ else:
898
+ structArray.append(IndexSorting(i, tempIndex))
899
+
900
+ # 인덱스 기준으로 정렬
901
+ structArray.sort(key=lambda x: x.newIndex)
902
+
903
+ # 정렬된 순서로 결과 배열 생성
904
+ sortedNameArray = []
905
+ for struct in structArray:
906
+ sortedNameArray.append(inNameArray[struct.oriIndex])
907
+
908
+ return sortedNameArray
909
+
910
+ def get_string(self, inStr):
911
+ """
912
+ 인덱스 부분을 제외한 이름 문자열 가져오기
913
+
914
+ Args:
915
+ inStr: 처리할 이름 문자열
916
+
917
+ Returns:
918
+ 인덱스가 제외된 이름 문자열
919
+ """
920
+ filChar = self._get_filtering_char(inStr)
921
+ nameArray = self.convert_name_to_array(inStr)
922
+ indexOrder = self.get_name_part_index("Index")
923
+
924
+ # 인덱스 부분 제거
925
+ returnNameArray = nameArray.copy()
926
+ returnNameArray[indexOrder] = ""
927
+
928
+ return self._combine(returnNameArray, filChar)
929
+
930
+ def gen_mirroring_name(self, inStr):
931
+ """
932
+ 미러링된 이름 생성 (측면 또는 앞/뒤 변경)
933
+
934
+ 이름에서 Side와 FrontBack namePart를 자동으로 검색하고,
935
+ 발견된 값의 semanticmapping weight와 가장 차이가 큰 값으로 교체합니다.
936
+
937
+ Args:
938
+ inStr: 처리할 이름 문자열
939
+
940
+ Returns:
941
+ 미러링된 이름 문자열
942
+ """
943
+ nameArray = self.convert_name_to_array(inStr)
944
+
945
+ for part in self._nameParts:
946
+ partName = part.get_name()
947
+ partType = part.get_type()
948
+ if (partType != NamePartType.REALNAME or partType != NamePartType.INDEX) and part.is_direction():
949
+ partIndex = self.get_name_part_index(partName)
950
+ foundName = self.get_name(partName, inStr)
951
+ opositeName = part.get_most_different_weight_value(foundName)
952
+ if opositeName and foundName != opositeName:
953
+ nameArray[partIndex] = opositeName
954
+
955
+ returnName = self._combine(nameArray, self._get_filtering_char(inStr))
956
+
957
+ return returnName
958
+
959
+ def replace_filtering_char(self, inStr, inNewFilChar):
960
+ """
961
+ 이름의 구분자 문자 변경
962
+
963
+ Args:
964
+ inStr: 처리할 이름 문자열
965
+ inNewFilChar: 새 구분자 문자
966
+
967
+ Returns:
968
+ 구분자가 변경된 이름 문자열
969
+ """
970
+ nameArray = self.convert_name_to_array(inStr)
971
+ return self._combine(nameArray, inNewFilChar)
972
+
973
+ def replace_name_part(self, inPart, inStr, inNewName):
974
+ """
975
+ 이름의 특정 부분을 새 이름으로 변경
976
+
977
+ Args:
978
+ inPart: 수정할 부분 ("Base", "Type", "Side", "FrontBack", "RealName", "Index")
979
+ inStr: 처리할 이름 문자열
980
+ inNewName: 새 이름
981
+
982
+ Returns:
983
+ 수정된 이름 문자열
984
+ """
985
+ nameArray = self.convert_name_to_array(inStr)
986
+ partIndex = self.get_name_part_index(inPart)
987
+
988
+ if partIndex >= 0:
989
+ nameArray[partIndex] = inNewName
990
+
991
+ newName = self._combine(nameArray, self._get_filtering_char(inStr))
992
+ newName = self.set_index_padding_num(newName)
993
+
994
+ return newName
995
+
996
+ def remove_name_part(self, inPart, inStr):
997
+ """
998
+ 이름의 특정 부분 제거
999
+
1000
+ Args:
1001
+ inPart: 제거할 부분 ("Base", "Type", "Side", "FrontBack", "RealName", "Index")
1002
+ inStr: 처리할 이름 문자열
1003
+
1004
+ Returns:
1005
+ 수정된 이름 문자열
1006
+ """
1007
+ nameArray = self.convert_name_to_array(inStr)
1008
+ partIndex = self.get_name_part_index(inPart)
1009
+
1010
+ if partIndex >= 0:
1011
+ nameArray[partIndex] = ""
1012
+
1013
+ newName = self._combine(nameArray, self._get_filtering_char(inStr))
1014
+ newName = self.set_index_padding_num(newName)
1015
+
1016
+ return newName
1017
+
1018
+ def load_from_config_file(self, configPath=None):
1019
+ """
1020
+ 설정 파일에서 설정 로드
1021
+
1022
+ Args:
1023
+ configPath: 설정 파일 경로 (기본값: self._configPath)
1024
+
1025
+ Returns:
1026
+ 로드 성공 여부 (True/False)
1027
+ """
1028
+ # 경로가 없으면 인스턴스 생성 시 설정된 경로 사용
1029
+ if not configPath:
1030
+ configPath = self._configPath
1031
+
1032
+ if not configPath:
1033
+ print("설정 파일 경로가 제공되지 않았습니다.")
1034
+ return False
1035
+
1036
+ # NamingConfig 인스턴스 생성 및 설정 로드
1037
+ config = NamingConfig()
1038
+ if config.load(configPath):
1039
+ # 설정을 Naming 인스턴스에 적용
1040
+ result = config.apply_to_naming(self)
1041
+ if result:
1042
+ self._configPath = configPath # 성공적으로 로드한 경로 저장
1043
+ return result
1044
+ else:
1045
+ print(f"설정 파일 로드 실패: {configPath}")
1046
+ return False
1047
+
1048
+ def load_default_config(self):
1049
+ """
1050
+ 기본 설정 로드 (현재는 아무 작업도 수행하지 않음)
1051
+
1052
+ Returns:
1053
+ 항상 True 반환 (기본 설정은 __init__에서 이미 설정됨)
1054
+ """
1055
+ # 이 메소드는 현재 __init__에서 설정한 기본값을 그대로 사용하므로
1056
+ # 아무 작업도 수행하지 않습니다.
1057
+ return True
1058
+
1059
+ def get_config_path(self):
1060
+ """
1061
+ 현재 설정 파일 경로 가져오기
1062
+
1063
+ Returns:
1064
+ 설정 파일 경로 (없으면 빈 문자열)
1065
+ """
1066
+ return self._configPath or ""