Skip to content

Instantly share code, notes, and snippets.

@AndrewDongminYoo
Created October 17, 2024 04:44
Show Gist options
  • Select an option

  • Save AndrewDongminYoo/759c2665cf25751884bea643616780e3 to your computer and use it in GitHub Desktop.

Select an option

Save AndrewDongminYoo/759c2665cf25751884bea643616780e3 to your computer and use it in GitHub Desktop.
Dart extension methods for applying camelCase and snake_case to strings
extension StringExtensions on String {
/// 문자열을 스네이크 케이스로 변환하는 `toSnakeCase()` 메서드를 사용하여 [String] 클래스를 확장
///
/// 스네이크 케이스는 단어는 밑줄(`_`)로 구분하고 모든 문자는 소문자로 구분하는 명명 규칙입니다.
/// 이 메서드는 문자열의 문자를 반복하여 문자열의 시작 부분에 없는 대문자 앞에 밑줄을 추가하고 모든 문자를 소문자로 변환
///
/// Example:
/// ```dart
/// 'HelloWorld'.toSnakeCase(); // 'hello_world'
/// 'XMLHTTPRequest'.toSnakeCase(); // 'xmlhttp_request'
/// ```
String toSnakeCase() {
// 변환된 문자열을 저장하기 위한 빈 StringBuffer
final buffer = StringBuffer();
// 이전 문자가 밑줄이었는지 여부를 추적하기 위해 부울 변수
var previousUnderscore = false;
// for 루프를 사용하여 입력 문자열의 각 문자를 반복
for (var i = 0; i < length; i++) {
// 각 문자에 대해 해당 문자가 공백(' ')인지 하이픈('-')인지 확인
if (this[i] == ' ' || this[i] == '-') {
// 이전 문자가 밑줄이 아닌 경우 버퍼에 밑줄('_')을 추가하고 previousUnderscore를 true로 설정
if (!previousUnderscore) {
buffer.write('_');
previousUnderscore = true;
}
// 두 조건 중 하나라도 참이면 버퍼에 밑줄('_')을 추가
// - 문자가 대문자인 경우 첫 번째 문자인지 또는 이전 문자가 밑줄이었는지
// - 이전 문자가 소문자인지 또는 다음 문자가 소문자인지
} else if (this[i].toUpperCase() == this[i] &&
this[i].toLowerCase() != this[i]) {
if (i != 0 && !previousUnderscore) {
// 현재 문자가 대문자이고 이전 문자가 소문자이거나 다음 문자가 소문자인 경우
if (this[i - 1].toLowerCase() == this[i - 1] ||
(i + 1 < length && this[i + 1].toLowerCase() == this[i + 1])) {
buffer.write('_');
}
}
// 밑줄 대소문자를 처리한 후 현재 문자의 소문자 버전을 버퍼에 추가하고 previousUnderscore를 false로 설정
buffer.write(this[i].toLowerCase());
previousUnderscore = false;
// 문자가 공백, 하이픈, 대문자가 아닌 경우 단순히 버퍼에 해당 문자를 추가하고 previousUnderscore를 false로 설정
} else {
buffer.write(this[i]);
previousUnderscore = false;
}
}
// 모든 문자를 반복한 후 toString() 메서드를 사용하여 버퍼를 문자열로 반환
return buffer.toString();
}
/// 문자열을 입력으로 받아 camelCase 형식(첫 단어는 소문자로, 그 이후의 각 단어는 대문자로 시작하는 명명 규칙)으로 변환하는 함수
///
/// 이 메서드는 단어가 아닌 문자(예: 공백, 구두점 등)와 일치하는 정규식을 사용하여 입력 문자열을 단어 배열로 분할합니다.
/// 그런 다음 단어를 반복하여 각 단어의 첫 글자는 대문자로, 나머지는 소문자로 변환합니다.
/// 결과 문자열은 첫 번째 문자가 소문자로 반환됩니다.
///
/// Example:
///
/// ```dart
/// 'hello_world'.toCamelCase(); // 'helloWorld'
/// 'XML_HTTP_REQUEST'.toCamelCase(); // 'xmlHttpRequest'
/// ```
String toCamelCase() {
// 먼저 단어가 아닌 모든 문자(예: 공백, 구두점 등)와 일치하는 정규식을 사용하여 입력 문자열을 단어 배열로 분할합니다.
final words = split(RegExp(r'[!@#<>?":`~;[\]\\|=+)(*&^%-\s_]+'));
// 입력 문자열이 비어 있거나 결과 단어 배열이 비어 있으면 빈 문자열을 반환합니다.
if (isEmpty || words.isEmpty) {
return '';
}
// 처리할 단어가 있는 경우 새 StringBuffer 객체를 생성하여 대/소문자 대/소문자 문자열을 만듭니다.
final buffer = StringBuffer();
// 그런 다음 배열의 각 단어를 반복합니다:
for (final word in words) {
// 단어가 비어 있지 않으면 단어의 첫 글자를 대문자로 하고 StringBuffer에 추가한 다음 나머지 단어는 소문자로 추가합니다.
if (word.isNotEmpty) {
buffer.write(word[0].toUpperCase() + word.substring(1).toLowerCase());
}
}
// 모든 단어를 처리한 후 StringBuffer를 문자열로 변환하여 출력 변수에 저장합니다.
final output = buffer.toString();
// 마지막으로 첫 번째 문자가 소문자로 된 새 문자열을 반환하고 나머지 출력 문자열을 반환합니다.
return output[0].toLowerCase() + output.substring(1);
}
}
// 📦 Package imports:
import 'package:flutter_test/flutter_test.dart';
// 🌎 Project imports:
import 'case_converter.dart';
void main() {
group('StringExtensions', () {
group('toSnakeCase', () {
test('converts camelCase to snake_case', () {
expect('camelCase'.toSnakeCase(), 'camel_case');
expect('snakeCase'.toSnakeCase(), 'snake_case');
expect('PascalCase'.toSnakeCase(), 'pascal_case');
});
test('handles leading and trailing uppercase characters', () {
expect('LeadingUppercase'.toSnakeCase(), 'leading_uppercase');
expect('TrailingUppercase'.toSnakeCase(), 'trailing_uppercase');
});
test('handles consecutive uppercase characters', () {
expect('HTTPRequest'.toSnakeCase(), 'http_request');
expect('XMLHTTPRequest'.toSnakeCase(), 'xmlhttp_request');
});
test('handles empty string', () {
expect(''.toSnakeCase(), '');
});
test('handles string with only lowercase characters', () {
expect('lowercase'.toSnakeCase(), 'lowercase');
});
test('handles string with only uppercase characters', () {
expect('UPPERCASE'.toSnakeCase(), 'uppercase');
});
test('handles string with Title Case', () {
expect('Awesome Title Case'.toSnakeCase(), 'awesome_title_case');
expect('MixedCaseString'.toSnakeCase(), 'mixed_case_string');
expect('mixedCaseString'.toSnakeCase(), 'mixed_case_string');
});
test('handles dash-case', () {
expect('dash-is-also-good'.toSnakeCase(), 'dash_is_also_good');
expect('string--with--dashes'.toSnakeCase(), 'string_with_dashes');
});
});
test('handles string with numbers', () {
expect('string123'.toSnakeCase(), 'string123');
expect('123string'.toSnakeCase(), '123string');
expect('string123String'.toSnakeCase(), 'string123_string');
});
test('handles string with special characters', () {
expect(r'string@#$%'.toSnakeCase(), r'string@#$%');
expect(r'@#$%string'.toSnakeCase(), r'@#$%string');
expect(r'string@#$%String'.toSnakeCase(), r'string@#$%_string');
});
test('handles string with consecutive spaces', () {
expect('string with spaces'.toSnakeCase(), 'string_with_spaces');
});
test('handles string with leading and trailing spaces', () {
expect(' leadingSpace '.toSnakeCase(), '_leading_space_');
expect(' leadingSpace'.toSnakeCase(), '_leading_space');
expect('trailingSpace '.toSnakeCase(), 'trailing_space_');
});
test('handles string with leading and trailing dashes', () {
expect('-leadingDash-'.toSnakeCase(), '_leading_dash_');
expect('-leadingDash'.toSnakeCase(), '_leading_dash');
expect('trailingDash-'.toSnakeCase(), 'trailing_dash_');
});
});
group('toCamelCase', () {
test('converts snake_case to camelCase', () {
expect('snake_case'.toCamelCase(), 'snakeCase');
expect(
'snake_case_with_multiple_words'.toCamelCase(),
'snakeCaseWithMultipleWords',
);
});
test('converts kebab-case to camelCase', () {
expect('kebab-case'.toCamelCase(), 'kebabCase');
expect(
'kebab-case-with-multiple-words'.toCamelCase(),
'kebabCaseWithMultipleWords',
);
});
test('converts space-separated words to camelCase', () {
expect('space separated words'.toCamelCase(), 'spaceSeparatedWords');
expect(
'multiple space separated words'.toCamelCase(),
'multipleSpaceSeparatedWords',
);
});
test('handles leading and trailing underscores', () {
expect('_leading_underscore'.toCamelCase(), 'leadingUnderscore');
expect('trailing_underscore_'.toCamelCase(), 'trailingUnderscore');
});
test('handles leading and trailing hyphens', () {
expect('-leading-hyphen'.toCamelCase(), 'leadingHyphen');
expect('trailing-hyphen-'.toCamelCase(), 'trailingHyphen');
});
test('handles leading and trailing spaces', () {
expect(' leading space'.toCamelCase(), 'leadingSpace');
expect('trailing space '.toCamelCase(), 'trailingSpace');
});
test('handles consecutive separators', () {
expect('snake__case'.toCamelCase(), 'snakeCase');
expect('kebab--case'.toCamelCase(), 'kebabCase');
expect('space separated words'.toCamelCase(), 'spaceSeparatedWords');
});
test('handles mixed separators', () {
expect('snake_kebab-case'.toCamelCase(), 'snakeKebabCase');
expect('kebab-snake_case'.toCamelCase(), 'kebabSnakeCase');
expect(
'space separated_kebab-case'.toCamelCase(),
'spaceSeparatedKebabCase',
);
});
test('handles empty string', () {
expect(''.toCamelCase(), '');
});
test('handles string with only uppercase characters', () {
expect('UPPERCASE'.toCamelCase(), 'uppercase');
});
test('handles string with only lowercase characters', () {
expect('lowercase'.toCamelCase(), 'lowercase');
});
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment