• [^] # Re: un bout de coquillage

    Posté par (site web personnel, Mastodon) . En réponse au message Avent du Code, jour 3. Évalué à 2. Dernière modification le 12 décembre 2022 à 01:47.

    La seconde partie m'a fait pensé à split pour les groupes de trois... Mais bon, ça fait pléthore de fichiers à gérer ensuite, et puis l'adaptation de la solution précédente n'est pas vraiment difficile (le truc en sus est d'arriver à compter ...modulo trois.)

    #!/bin/sh
    # 1ドル: input file
    for c in 'cat' 'fold' 'grep' 'sort' 'test'
    do
     if ! command -v "$c" >/dev/null
     then
     echo "Error: command '$c' not found" >&2
     exit 3
     fi
    done
    if test -z "1ドル"
    then
     echo "Please call me with an input file..." >&2
     exit 1
    fi
    if grep -Eqsv '^[A-Za-z]+$' "1ドル"
    then
     echo "Found invalid line, check the file!" >&2
     exit 2
    fi
    _if="1ドル"
    if test $(( $( cat "$_if" | wc -l ) % 3 )) -ne 0
    then
     echo "Number of lines not multiple of 3" >&2
     exit 2
    fi
    _fc=$( mktemp ) # becomes first rucksack
    _sc=$( mktemp ) # becomes second rucksack
    _tc=$( mktemp ) # third rucksack
    _si='' # shared items
    _gc=0 # group counter
    _bl='' # badges list
    while IFS= read -r line <&3
    do
     _gc=$(( _gc + 1 ))
     case $(( _gc % 3 )) in
     1) # 1st member of group
     printf '%s' "$line" | fold -w 1 | sort -uo "$_fc"
     ;;
     2) # 2nd member of group
     printf '%s' "$line" | fold -w 1 | sort -uo "$_sc"
     _si="$( comm -12 "$_fc" "$_sc" )"
     ;;
     0) # 3rd member of group
     printf '%s' "$line" | fold -w 1 | sort -uo "$_tc"
     _bl="$_bl$( printf '%s' "$_si" | comm -12 "$_tc" - )"
     ;;
     *) echo "?!?$_gc!?!" >&2 ;;
     esac
    done 3<"$_if"
    rm "$_fc" "$_sc" "$_tc"
    #echo "$_bl" | cat -vet
    _ps=0 # priority sum
    _ac=0 # ASCII code
    for character in $( echo "$_bl" )
    do
     _ac=$( printf '%d' "'$character" )
     case "$character" in
     [a-z]) # a is 97 but should translate to 1
     _ps=$(( _ps + _ac - 96 )) ;;
     [A-Z]) # A is 65 but should translate to 27
     _ps=$(( _ps + _ac - 38 )) ;;
     *) echo "$character=$_ac=??" >&2 ;;
     esac
    done
    echo "$_ps"

    Le vice avait été poussé jusqu'à éviter grep -o car cette option n'est pas POSIX (bien que je la trouve un peu partout ceci dit.) Ici, je propose une autre approche que j'avais mentionnée dans l'un de mes journaux. En terme de perfs, faut voir.

    $ time echo "split" | sed 's/./&\n/g'
    s
    p
    l
    i
    t
    real 0m0.014s
    user 0m0.002s
    sys 0m0.004s
    $ time echo "split" | grep -o '.'
    s
    p
    l
    i
    t
    real 0m0.006s
    user 0m0.002s
    sys 0m0.004s
    $ time echo "split" | fold -w1
    s
    p
    l
    i
    t
    real 0m0.008s
    user 0m0.002s
    sys 0m0.007s

    Il y a certainement des optimisations possibles, mais comme on le sait faut pas s'y lancer prématurément.

    "It is seldom that liberty of any kind is lost all at once." ― David Hume