글자 Byte 계산 (SMS발송 등...)

2025. 8. 18. 14:46·Web/JS & jQuery

 

jQuery로 작성된 바이트 체크 샘플
SMS 발송 관련 페이지에서 주로 사용된다.


소스코드의 자바스크립트 영역에서 2가지 방식을 지정해서 사용하면 된다.

1. const MAX_BYTES = 100;
 - 허용가능한 최대 byte 수 
2. const useUtf8Calculation = true; 
 - UTF8 형태로 byte를 계산할지 여부 (영문2, 한글3, 이모지4) 
3. const textInput = $('#text-input'); 
 - 입력 영역 지정 (textarea 를 지정한다. 이 부분은 키입력 이벤트와 이모지 등에서 사용된다)

 

ByteCheck.html
0.01MB

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>실시간 바이트 체크 프로그램</title>
    <!-- Tailwind CSS CDN -->
    <script src="https://cdn.tailwindcss.com"></script>
    <!-- jQuery CDN -->
    <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
    <style>
        /* 기본 폰트 및 배경 설정 */
        body {
            font-family: 'Inter', sans-serif;
        }
        /* 이모지 팝업 기본 숨김 */
        #emoji-modal {
            display: none;
        }
        /* 스크롤바 디자인 */
        #emoji-grid::-webkit-scrollbar {
            width: 8px;
        }
        #emoji-grid::-webkit-scrollbar-track {
            background: #f1f1f1;
            border-radius: 10px;
        }
        #emoji-grid::-webkit-scrollbar-thumb {
            background: #888;
            border-radius: 10px;
        }
        #emoji-grid::-webkit-scrollbar-thumb:hover {
            background: #555;
        }
    </style>
</head>
<body class="bg-slate-100 flex items-center justify-center min-h-screen">

    <div class="w-full max-w-2xl mx-auto p-6 md:p-8 bg-white rounded-2xl shadow-lg">
        <h1 class="text-2xl md:text-3xl font-bold text-slate-800 mb-4 text-center">실시간 바이트 체크</h1>
        <!-- 설명 문구에 ID 추가 -->
        <p id="description" class="text-slate-600 mb-6 text-center"></p>
        
        <!-- 글자 입력 폼 -->
        <div class="relative">
            <textarea id="text-input" class="w-full h-64 p-4 border border-slate-300 rounded-xl resize-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition duration-200" placeholder="여기에 텍스트를 입력하세요..."></textarea>
        </div>

        <!-- 바이트 표시 및 버튼 영역 -->
        <div class="flex justify-between items-center mt-4">
            <div class="flex gap-2">
                <button id="clear-btn" class="px-4 py-2 bg-red-500 text-white font-semibold rounded-lg hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 transition-colors duration-200">
                    모두 지우기
                </button>
                <button id="emoji-btn" class="px-4 py-2 bg-yellow-500 text-white font-semibold rounded-lg hover:bg-yellow-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-yellow-500 transition-colors duration-200">
                    이모지
                </button>
            </div>
            <div id="byte-counter" class="text-lg font-semibold text-slate-700 bg-slate-200 px-4 py-2 rounded-lg">
                0 / 100 byte
            </div>
        </div>
    </div>

    <!-- 이모지 선택 팝업 (Modal) -->
    <div id="emoji-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
        <div class="bg-white rounded-2xl shadow-xl p-6 w-full max-w-md">
            <div class="flex justify-between items-center mb-4">
                <h3 class="text-xl font-bold text-slate-800">이모지 선택</h3>
                <button id="close-modal-btn" class="text-slate-500 hover:text-slate-800 text-2xl">&times;</button>
            </div>
            <div id="emoji-grid" class="grid grid-cols-8 gap-2 text-2xl text-center h-64 overflow-y-auto pr-2">
                <!-- 이모지가 여기에 동적으로 추가됩니다. -->
            </div>
        </div>
    </div>


    <script>
        $(document).ready(function() {
            const MAX_BYTES = 100;
            // true: UTF-8 정확한 계산 (한글 3, 이모지 4바이트)
            // false: 단순 계산 (영문 외 2바이트)
            const useUtf8Calculation = true; 
            const textInput = $('#text-input');
            
            // 페이지 로드 시 설명 문구를 MAX_BYTES 값에 맞춰 동적으로 설정
            $('#description').text(`내용을 입력하면 실시간으로 바이트를 계산합니다. (최대 ${MAX_BYTES}바이트)`);

            /**
             * @description 입력된 문자열의 바이트를 계산하는 함수 (UTF-8 또는 단순 계산)
             * @param {string} str - 바이트를 계산할 문자열
             * @returns {number} 계산된 바이트 수
             */
            function checkByte(str) {
                let totalBytes = 0;
                if (useUtf8Calculation) {
                    // UTF-8 정확한 계산
                    for (let i = 0; i < str.length; i++) {
                        const charCode = str.charCodeAt(i);
                        if (charCode < 0x80) { // 1바이트
                            totalBytes += 1;
                        } else if (charCode < 0x800) { // 2바이트
                            totalBytes += 2;
                        } else if (charCode < 0xD800 || charCode >= 0xE000) { // 3바이트 (한글 포함)
                            totalBytes += 3;
                        } else { // 4바이트 (이모지 등)
                            totalBytes += 4;
                            i++; // 서로게이트 페어이므로 다음 문자 건너뛰기
                        }
                    }
                } else {
                    // 단순 계산 (영문 1, 그 외 2바이트)
                    for (let i = 0; i < str.length; i++) {
                        const charCode = str.charCodeAt(i);
                        totalBytes += (charCode > 127) ? 2 : 1;
                    }
                }
                return totalBytes;
            }

            /**
             * @description 최대 바이트를 초과한 경우 문자열을 잘라내는 함수
             * @param {string} str - 원본 문자열
             * @param {number} maxBytes - 최대 허용 바이트
             * @returns {string} 최대 바이트에 맞게 잘라낸 문자열
             */
            function truncateText(str, maxBytes) {
                let currentBytes = 0;
                let truncatedStr = '';

                for (let i = 0; i < str.length; i++) {
                    const charCode = str.charCodeAt(i);
                    let charByte = 0;

                    if (useUtf8Calculation) {
                        // UTF-8 바이트 크기 결정
                        if (charCode < 0x80) charByte = 1;
                        else if (charCode < 0x800) charByte = 2;
                        else if (charCode < 0xD800 || charCode >= 0xE000) charByte = 3;
                        else { charByte = 4; }
                    } else {
                        // 단순 계산 바이트 크기 결정
                        charByte = (charCode > 127) ? 2 : 1;
                    }

                    if (currentBytes + charByte > maxBytes) {
                        break; // 최대 바이트를 넘으면 루프 종료
                    }
                    
                    currentBytes += charByte;
                    truncatedStr += str.charAt(i);
                    // 4바이트 문자(이모지)인 경우, 서로게이트 페어의 뒷부분도 포함
                    if (charByte === 4) {
                        truncatedStr += str.charAt(i + 1);
                        i++;
                    }
                }
                return truncatedStr;
            }

            /**
             * @description UI에 현재 바이트 수를 업데이트하는 함수
             * @param {number} current - 현재 바이트
             * @param {number} max - 최대 바이트
             */
            function updateByteDisplay(current, max) {
                $('#byte-counter').text(`${current} / ${max} byte`);
                if (current >= max) {
                    $('#byte-counter').removeClass('text-slate-700').addClass('text-red-600 font-bold');
                } else {
                    $('#byte-counter').removeClass('text-red-600 font-bold').addClass('text-slate-700');
                }
            }

            // 텍스트 입력 영역에서 키보드 입력이 발생할 때마다 실행
            textInput.on('input keyup', function() {
                let content = $(this).val();
                let currentBytes = checkByte(content);

                if (currentBytes > MAX_BYTES) {                    
                    // 필요 시 아래 주석을 해제하여 알림창을 활성화할 수 있습니다.
                    // alert('허용된 글자수를 초과하였습니다');
                    
                    const truncatedContent = truncateText(content, MAX_BYTES);
                    $(this).val(truncatedContent);
                    currentBytes = checkByte(truncatedContent);
                }

                updateByteDisplay(currentBytes, MAX_BYTES);
            });

            // '모두 지우기' 버튼 클릭 시 실행
            $('#clear-btn').on('click', function() {
                textInput.val('');
                updateByteDisplay(0, MAX_BYTES);
                textInput.focus();
            });

            
            const emojis = [
                '😀', '😃', '😄', '😁', '😆', '😅', '😂', '🤣', '😊', '😇', '🙂', '🙃', '😉', '😌', '😍', '🥰', '😘', '😗', '😙', '😚', '😋', '😛',
                '😜', '🤪', '🤨', '🧐', '🤓', '😎', '🤩', '🥳', '😏', '😒', '😞', '�', '😟', '😕', '🙁', '☹️', '😣', '😖', '😫', '😩', '🥺', '😢',
                '😭', '😤', '😠', '😡', '🤬', '🤯', '😳', '🥵', '🥶', '😱', '😨', '😰', '😥', '😓', '🤗', '🤔', '🤭', '🤫', '🤥', '😶', '😐', '😑',
                '😬', '🙄', '😯', '😦', '😧', '😮', '😲', '🥱', '😴', '🤤', '😪', '😵', '🤐', '🥴', '🤢', '🤮', '🤧', '😷', '🤒', '🤕', '🤑', '🤠',
                '❤️', '🧡', '💛', '💚', '💙', '💜', '🤎', '🖤', '🤍', '💔', '❣️', '💕', '💞', '💓', '💗', '💖', '💘', '💝', '💟', '👍', '👎', '👌',
                '👋', '🤚', '🖐️', '✋', '🖖', '👌', '🤏', '✌️', '🤞', '🤟', '🤘', '🤙', '👈', '👉', '👆', '🖕', '👇', '☝️', '👍', '👎', '✊', '👊',
                '🤛', '🤜', '👏', '🙌', '👐', '🤲', '🤝', '🙏', '✍️', '💅', '🤳', '💪', '🦾', '🦵', '🦿', '🦶', '👣', '👀', '👁️', '🧠', '🦴', '🦷',
                '👅', '👄', '👶', '👧', '🧒', '👦', '👩', '🧑', '👨', '👩‍🦱', '🧑‍', '👨‍🦱', '👩‍🦰', '🧑‍🦰', '👨‍🦰', '👱‍♀️', '👱', '👱‍♂️', '👩‍🦳', '🧑‍🦳', '👨‍🦳',
                '🐶', '🐱', '🐭', '🐹', '🐰', '🦊', '🐻', '🐼', '🐨', '🐯', '🦁', '🐮', '🐷', '🐽', '🐸', '🐵', '🙈', '🙉', '🙊', '🐒', '🐔', '🐧',
                '🐦', '🐤', '🐣', '🐥', '🦆', '🦅', '🦉', '🦇', '🐺', '🐗', '🐴', '🦄', '🐝', '🐛', '🦋', '🐌', '🐞', '🐜', '🦟', '🦗', '🕷️', '🕸️',
                '🔥', '✨', '⭐', '🌟', '💫', '💥', '☄️', '☀️', '🌤️', '⛅', '🌥️', '🌦️', '🌈', '☁️', '🌧️', '⛈️', '🌩️', '⚡', '❄️', '🌨️', '☃️',
                '⛄', '🌬️', '💨', '💧', '💦', '🌊', '🎄', '🎉', '🎊', '🎈', '🎁', '💯', '🚀', '✅', '☑️', '✔️'
            ];
            const emojiGrid = $('#emoji-grid');
            
            emojis.forEach(emoji => {
                const emojiButton = $('<button class="p-1 rounded-lg hover:bg-slate-200 transition-colors"></button>').text(emoji);
                emojiGrid.append(emojiButton);
            });

            $('#emoji-btn').on('click', function() {
                $('#emoji-modal').fadeIn(200);
            });

            $('#close-modal-btn, #emoji-modal').on('click', function(e) {
                if (e.target === this) {
                    $('#emoji-modal').fadeOut(200);
                }
            });

            $('#emoji-grid').on('click', 'button', function() {
                const emoji = $(this).text();
                const textarea = textInput[0];
                const start = textarea.selectionStart;
                const end = textarea.selectionEnd;
                const text = textInput.val();
                
                const newText = text.substring(0, start) + emoji + text.substring(end);
                textInput.val(newText);
                
                textarea.focus();
                textarea.selectionStart = textarea.selectionEnd = start + emoji.length;
                
                textInput.trigger('input');
                
                $('#emoji-modal').fadeOut(200);
            });

            // 페이지 로드 시 초기 상태 설정
            updateByteDisplay(0, MAX_BYTES);
        });
    </script>

</body>
</html>

 

 

'Web > JS & jQuery' 카테고리의 다른 글

jQuery 를 사용한 아코디언 형태의 [상품정보 더보기]  (0) 2025.09.24
jQuery + Ajax 무한 스크롤 (페이징)  (0) 2025.09.03
동적 form 전송  (2) 2025.07.28
JS와 jQuery 를 사용한 모듈화  (0) 2024.09.26
유효성 검사  (1) 2024.09.03
'Web/JS & jQuery' 카테고리의 다른 글
  • jQuery 를 사용한 아코디언 형태의 [상품정보 더보기]
  • jQuery + Ajax 무한 스크롤 (페이징)
  • 동적 form 전송
  • JS와 jQuery 를 사용한 모듈화
iyak
iyak
자료 정리
  • iyak
    iyak
    나의 정리 공간

    post | manage
  • 전체
    오늘
    어제
    • 분류 전체보기 (57)
      • C#.NET (30)
        • C# (9)
        • ASP.NET (19)
        • WinForm (0)
        • 설정 (2)
      • JAVA,Spring (0)
        • Spring (0)
      • DB (9)
        • SQLServer (9)
        • MySQL & MaridDB (0)
      • Web (14)
        • JS & jQuery (12)
        • Web개발 관련사이트 (2)
      • 기타 (4)
        • 프로그램 (4)
  • 블로그 메뉴

    • 홈
    • 태그
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
iyak
글자 Byte 계산 (SMS발송 등...)
상단으로

티스토리툴바