export class StringUtil {
//==================================================================================
/** PascalCase / camelCase / UPPER_SNAKE / lower_snake / kebab-case -> lower_snake
*///================================================================================
// ! NOTE: 벤치마크 결과 정규식 사용 방식에 비해 30% ~ 200% 성능 향상
public static ToLowerSnake(word: string) {
if(StringUtil.IsNullOrWhiteSpace(word)) return word;
let result = '';
let prevLowerOrNum = false;
for (let i = 0; i < word.length; i++) {
const char = word[i];
if (char === '-' || char === ' ' || char === '_') {
if (result[result.length - 1] !== '_') result += '_';
prevLowerOrNum = false;
continue;
}
if (char >= 'A' && char <= 'Z') {
if (prevLowerOrNum && result[result.length - 1] !== '_') result += '_';
result += char.toLowerCase();
prevLowerOrNum = false;
} else {
result += char;
prevLowerOrNum = (char >= 'a' && char <= 'z') || (char >= '0' && char <= '9');
}
}
return result;
}
//==================================================================================
/** PascalCase / camelCase / UPPER_SNAKE / lower_snake / kebab-case -> UPPSER_SNAKE
*///================================================================================
public static ToUppserSnake(word: string) {
return StringUtil.ToLowerSnake(word).toUpperCase();
}
//==================================================================================
/** PascalCase / camelCase / UPPER_SNAKE / lower_snake / kebab-case -> kebab-case
*///================================================================================
public static ToKebabCase(word: string) {
if(StringUtil.IsNullOrWhiteSpace(word)) return word;
let result = '';
let prevLowerOrNum = false;
for (let i = 0; i < word.length; i++) {
const char = word[i];
if (char === '-' || char === ' ' || char === '_') {
if (result[result.length - 1] !== '-') result += '-';
prevLowerOrNum = false;
continue;
}
if (char >= 'A' && char <= 'Z') {
if (prevLowerOrNum && result[result.length - 1] !== '-') result += '-';
result += char.toLowerCase();
prevLowerOrNum = false;
} else {
result += char;
prevLowerOrNum = (char >= 'a' && char <= 'z') || (char >= '0' && char <= '9');
}
}
return result;
}
//==================================================================================
/** PascalCase / camelCase / UPPER_SKANE / lower_snake / kebab-case -> camelCase
*///================================================================================
/** 모든 형태의 문자열을 camelCase로 변환 */
public static ToCamelCase(word: string): string {
if (StringUtil.IsNullOrWhiteSpace(word)) return word;
const words = StringUtil.ToWords(word);
return words[0] + words.slice(1).map(w => w[0].toUpperCase() + w.slice(1)).join('');
}
//==================================================================================
/** PascalCase / camelCase / UPPER_SKANE / lower_snake / kebab-case -> PascalCase
*///================================================================================
public static ToPascalCase(word: string): string {
if (StringUtil.IsNullOrWhiteSpace(word)) return word;
return StringUtil.ToWords(word).map(w => w[0].toUpperCase() + w.slice(1)).join('');
}
//==================================================================================
/** snake_case / SNAKE_CASE -> camelCase
*///================================================================================
public static SnakeToCamel(snakeCase: string) {
return snakeCase.toLowerCase()
.replace(/_+([a-z])/g, (m, $1) => $1.toUpperCase());
};
//==================================================================================
/** snake_case / SNAKE_CASE -> PascalCase
*///================================================================================
public static SnakeToPascal(snakeCase: string) {
const camel = snakeCase.toLowerCase()
.replace(/_+([a-z])/g, (m, $1) => $1.toUpperCase());
return camel[0].toUpperCase() + camel.substring(1);
};
//==================================================================================
/** 대상이 null이거나 빈 문자열인지 검사
*///================================================================================
public static IsNullOrEmpty(str: string): boolean {
return (str == null) || str.length === 0;
}
//==================================================================================
/** 대상이 null이거나 빈 문자열이거나 공백으로만 이루어진 문자열인지 검사
*///================================================================================
public static IsNullOrWhiteSpace(str: string): boolean {
return !str || !str.trim();
}
//==================================================================================
/** str이 words의 문자열 중 하나라도 포함하는지 검사
*///================================================================================
public static IncludeAny(str: string, words: string[]): boolean {
return words.some(word => str.includes(word));
}
/** 문자열을 단어 배열로 분리 (모든 케이스 대응) */
public static ToWords(word: string): string[] {
const words: string[] = [];
let currentWord = '';
for (let i = 0; i < word.length; i++) {
const char = word[i];
const prevChar = i > 0 ? word[i - 1] : '';
if (['_', '-', ' '].includes(char)) {
if (currentWord) {
words.push(currentWord);
currentWord = '';
}
continue;
}
const isUpper = char >= 'A' && char <= 'Z';
const isPrevLowerOrDigit = prevChar >= 'a' && prevChar <= 'z' || prevChar >= '0' && prevChar <= '9';
if (isUpper && currentWord && isPrevLowerOrDigit) {
words.push(currentWord);
currentWord = char;
} else {
currentWord += char;
}
}
if (currentWord) {
words.push(currentWord);
}
return words.map(w => w.toLowerCase());
}
}