DEV Community

ahandsel
ahandsel

Posted on

Script to generate ASCII, Full-width, and Half-Width characters

Here is a quick script I created to test the max character limits for a project. I needed to verify whether it worked as expected for ASCII, Japanese full-width, and Japanese half-width characters.

Hope it can be helpful for your project.

#!/usr/bin/env bash
set -euo pipefail

#-----------------------------------------------------------------------------#
# Script Name   : generate-test-string.sh
# Usage         : ./generate-test-string.sh [length] [character_type]
# Purpose       : Generate a cyclic string of given length using ASCII digits,
#                 full-width digits, or half-width Katakana characters.
# Version       : 1.3.0
#-----------------------------------------------------------------------------#

LOG_FILE="./generate-test-string.log"

#-------------------------------------------------------------------------------
# Utility functions
#-------------------------------------------------------------------------------

die() {
    local msg="$1"
    echo "Error: $msg" >&2
    exit 1
}

# Trap interrupts and errors
trap 'die "Script interrupted by user."' INT TERM
trap 'die "An unexpected error occurred."' ERR

# Ensure the log file is writable
touch "$LOG_FILE" >/dev/null 2>&1 || die "Cannot write to log file '$LOG_FILE'."

log() {
    local message="$1"
    # Replace home directory with '~'
    local msg="${message//$HOME/~}"
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $msg" >> "$LOG_FILE"
}

usage() {
    cat <<EOF
Usage: ${0##*/} [length] [character_type]
Generate a cyclic string of given length using:
  ASCII       - digits 1-0
  full-width  - digits 1-0  (or "full")
  half-width  - Katakana ア-ン  (or "half")

Options:
  -h, --help    Show this help message and exit.
EOF
}

validate_length() {
    [[ "$1" =~ ^[0-9]+$ ]] || die "Length must be a positive integer."
}

get_next_filename() {
    local base="test-string-v"
    local ext=".txt"
    local num=1
    local fname
    while :; do
        fname="${base}${num}${ext}"
        [ ! -e "$fname" ] && echo "$fname" && return
        num=$((num + 1))
    done
}

generate_string() {
    local length="$1"
    local type="$2"
    local -a chars

    case "$type" in
        ASCII)
            chars=(1 2 3 4 5 6 7 8 9 0)
            ;;
        full-width)
            chars=(1 2 3 4 5 6 7 8 9 0)
            ;;
        half-width)
            chars=(ア イ ウ エ オ カ キ ク ケ コ  \
                   サ シ ス セ ソ タ チ ツ テ ト  \
                   ナ ニ ヌ ネ ノ ハ ヒ フ ヘ ホ  \
                   マ ミ ム メ モ ラ リ ル レ ロ  \
                   ワ ヲ ン)
            ;;
        *)
            die "Unsupported character type: '$type'."
            ;;
    esac

    local total=${#chars[@]}
    local output=""
    for (( i=0; i<length; i++ )); do
        output+="${chars[i % total]}"
    done
    echo "$output"
}

#-------------------------------------------------------------------------------
# Main
#-------------------------------------------------------------------------------

main() {
    # Parse options
    while [[ "${1:-}" == -* ]]; do
        case "$1" in
            -h|--help) usage; exit 0 ;;
            *) die "Unknown option: $1. Use --help." ;;
        esac
    done

    local length_input="${1:-}"
    local char_type_raw="${2:-}"

    # Prompt for length if not provided
    if [ -z "$length_input" ]; then
        read -rp "Enter the length of the string to generate: " length_input
    fi
    validate_length "$length_input"

    # Prompt for character type if not provided
    if [ -z "$char_type_raw" ]; then
        echo "Select character type (default: ASCII):"
        echo "  ASCII       - digits 1-0"
        echo "  full-width  - digits 1-0  (or 'full')"
        echo "  half-width  - Katakana ア-ン  (or 'half')"
        read -rp "Enter character type [ASCII|full-width|half-width]: " char_type_raw
        : "${char_type_raw:=ASCII}"
    fi

    local lower
    lower="$(printf '%s' "$char_type_raw" | tr '[:upper:]' '[:lower:]')"
    case "$lower" in
        ascii)        char_type="ASCII" ;;
        full|full-width)
                      char_type="full-width" ;;
        half|half-width)
                      char_type="half-width" ;;
        *)            die "Invalid character type: '$char_type_raw'. Must be ASCII, full(-width), or half(-width)." ;;
    esac

    # Generate the string
    local result
    result="$(generate_string "$length_input" "$char_type")"

    # Find next available filename
    local filename
    filename="$(get_next_filename)"

    # Write to file
    if ! printf '%s' "$result" > "$filename"; then
        die "Failed to write output to '$filename'."
    fi

    # Determine relative script path
    local script_abs
    script_abs="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/$(basename "${BASH_SOURCE[0]}")"
    local rel_path="${script_abs/#$PWD\//./}"

    # Log the action
    log "Generated ${length_input}-character string of type '${char_type}' to file '${filename}' from ${rel_path}"

    echo "String written to ./${filename}"
}
main "$@"
Enter fullscreen mode Exit fullscreen mode

Top comments (0)