Come convertire una stringa in minuscolo in Bash?


Risposte:


2182

Esistono vari modi:

Standard POSIX

TR

$ echo "$a" | tr '[:upper:]' '[:lower:]'
hi all

AWK

$ echo "$a" | awk '{print tolower($0)}'
hi all

Non-POSIX

È possibile riscontrare problemi di portabilità con i seguenti esempi:

Bash 4.0

$ echo "${a,,}"
hi all

sed

$ echo "$a" | sed -e 's/\(.*\)/\L\1/'
hi all
# this also works:
$ sed -e 's/\(.*\)/\L\1/' <<< "$a"
hi all

Perl

$ echo "$a" | perl -ne 'print lc'
hi all

bash

lc(){
    case "$1" in
        [A-Z])
        n=$(printf "%d" "'$1")
        n=$((n+32))
        printf \\$(printf "%o" "$n")
        ;;
        *)
        printf "%s" "$1"
        ;;
    esac
}
word="I Love Bash"
for((i=0;i<${#word};i++))
do
    ch="${word:$i:1}"
    lc "$ch"
done

Nota: YMMV su questo. Non funziona per me (GNU bash versione 4.2.46 e 4.0.33 (e lo stesso comportamento 2.05b.0 ma nocasematch non è implementato)) anche con l'utilizzo shopt -u nocasematch;. Annullando l'impostazione di nocasematch, [["fooBaR" == "FOObar"]] corrisponde a OK MA all'interno del caso stranamente [bz] viene erroneamente identificato da [AZ]. Bash è confuso dal doppio negativo ("unsas nocasematch")! :-)


9
Mi sto perdendo qualcosa o il tuo ultimo esempio (in Bash) fa effettivamente qualcosa di completamente diverso? Funziona con "ABX", ma se invece fai word="Hi All"come gli altri esempi, ritorna ha, no hi all. Funziona solo con le lettere maiuscole e salta le lettere già minuscole.
Jangosteve,

26
Si noti che solo gli esempi tre awksono specificati nello standard POSIX.
Richard Hansen,

178
tr '[:upper:]' '[:lower:]'utilizzerà le impostazioni internazionali correnti per determinare gli equivalenti maiuscoli / minuscoli, quindi funzionerà con i locali che usano lettere con segni diacritici.
Richard Hansen,

10
Come si ottiene l'output in una nuova variabile? Vale a dire che voglio la stringa in minuscolo in una nuova variabile?
Adam Parkin,

60
@Adam:b="$(echo $a | tr '[A-Z]' '[a-z]')"
Tino

435

In Bash 4:

In minuscolo

$ string="A FEW WORDS"
$ echo "${string,}"
a FEW WORDS
$ echo "${string,,}"
a few words
$ echo "${string,,[AEIUO]}"
a FeW WoRDS

$ string="A Few Words"
$ declare -l string
$ string=$string; echo "$string"
a few words

Maiuscolo

$ string="a few words"
$ echo "${string^}"
A few words
$ echo "${string^^}"
A FEW WORDS
$ echo "${string^^[aeiou]}"
A fEw wOrds

$ string="A Few Words"
$ declare -u string
$ string=$string; echo "$string"
A FEW WORDS

Attiva / disattiva (non documentato, ma facoltativamente configurabile in fase di compilazione)

$ string="A Few Words"
$ echo "${string~~}"
a fEW wORDS
$ string="A FEW WORDS"
$ echo "${string~}"
a FEW WORDS
$ string="a few words"
$ echo "${string~}"
A few words

Capitalizzare (non documentato, ma facoltativamente configurabile in fase di compilazione)

$ string="a few words"
$ declare -c string
$ string=$string
$ echo "$string"
A few words

Caso del titolo:

$ string="a few words"
$ string=($string)
$ string="${string[@]^}"
$ echo "$string"
A Few Words

$ declare -c string
$ string=(a few words)
$ echo "${string[@]}"
A Few Words

$ string="a FeW WOrdS"
$ string=${string,,}
$ string=${string~}
$ echo "$string"
A few words

Per disattivare un declareattributo, utilizzare +. Ad esempio declare +c string,. Ciò influisce sulle assegnazioni successive e non sul valore corrente.

Le declareopzioni cambiano l'attributo della variabile, ma non il contenuto. Le riassegnazioni nei miei esempi aggiornano i contenuti per mostrare le modifiche.

Modificare:

Aggiunto " attiva / disattiva il primo carattere per parola" ( ${var~}) come suggerito da ghostdog74 .

Modifica: corretto comportamento della tilde per abbinare Bash 4.3.


5
Abbastanza bizzare, gli operatori "^^" e ",," non funzionano su caratteri non ASCII ma "~~" fa ... Quindi string="łódź"; echo ${string~~}restituirà "ŁÓDŹ", ma echo ${string^^}restituisce "łóDź". Anche dentro LC_ALL=pl_PL.utf-8. Sta usando bash 4.2.24.
Hubert Kario,

2
@HubertKario: è strano. È lo stesso per me in Bash 4.0.33 con la stessa stringa in en_US.UTF-8. È un bug e l'ho segnalato.
In pausa fino a nuovo avviso.

1
@HubertKario: Try echo "$string" | tr '[:lower:]' '[:upper:]'. Probabilmente mostrerà lo stesso fallimento. Quindi il problema non è almeno in parte di Bash.
In pausa fino a nuovo avviso.

1
@DennisWilliamson: Sì, l'ho notato anch'io (vedi commento alla risposta di Shuvalov). Direi solo "questa roba è solo per ASCII", ma poi è l'operatore "~~" che funziona, quindi non è che il codice e le tabelle di traduzione non siano già lì ...
Hubert Kario

4
@HubertKario: il manutentore di Bash ha riconosciuto il bug e ha dichiarato che verrà risolto nella prossima versione.
In pausa fino a nuovo avviso.

123
echo "Hi All" | tr "[:upper:]" "[:lower:]"

4
@RichardHansen: trnon funziona per me per i personaggi non ACII. Ho un set di impostazioni internazionali corretto e file di localizzazione generati. Hai idea di cosa potrei fare di sbagliato?
Hubert Kario,

Cordiali saluti: Questo ha funzionato su Windows / Msys. Alcuni degli altri suggerimenti no.
wasatchwizard,

3
Perché è [:upper:]necessario
mgutt

77

tr :

a="$(tr [A-Z] [a-z] <<< "$a")"

AWK :

{ print tolower($0) }

sed :

y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/

2
+1 a="$(tr [A-Z] [a-z] <<< "$a")"mi sembra più semplice. Sono ancora un principiante ...
Sandeepan Nath,

2
Consiglio vivamente la sedsoluzione; Ho lavorato in un ambiente che per qualche ragione non ha, trma non ho ancora trovato un sistema senza sed, e per la maggior parte del tempo che voglio farlo, ho appena fatto qualcos'altro in sedmodo da poter fare catena i comandi insieme in una singola (lunga) istruzione.
Haravikk,

2
Le espressioni tra parentesi dovrebbero essere citate. In tr [A-Z] [a-z] A, la shell può eseguire l'espansione del nome file se ci sono nomi di file costituiti da una sola lettera o è impostato nullgob . tr "[A-Z]" "[a-z]" Asi comporterà correttamente.
Dennis,

2
@CamiloMartin è un sistema BusyBox in cui sto riscontrando quel problema, in particolare i NAS Synology, ma l'ho riscontrato anche su alcuni altri sistemi. Ultimamente ho fatto un sacco di scripting shell multipiattaforma e con il requisito che non sia stato installato nulla in più rende le cose molto difficili! Tuttavia non ho ancora incontrato un sistema senzased
Haravikk,

2
Si noti che tr [A-Z] [a-z]non è corretto in quasi tutte le versioni locali. ad esempio, nella en-USlocale, A-Zè in realtà l'intervallo AaBbCcDdEeFfGgHh...XxYyZ.
fuz,

44

So che questo è un post vecchio ma ho fatto questa risposta per un altro sito, quindi ho pensato di pubblicarlo qui:

UPPER -> lower : usa python:

b=`echo "print '$a'.lower()" | python`

O Ruby:

b=`echo "print '$a'.downcase" | ruby`

O Perl (probabilmente il mio preferito):

b=`perl -e "print lc('$a');"`

O PHP:

b=`php -r "print strtolower('$a');"`

O Awk:

b=`echo "$a" | awk '{ print tolower($1) }'`

O Sed:

b=`echo "$a" | sed 's/./\L&/g'`

O Bash 4:

b=${a,,}

O NodeJS se ce l'hai (e sei un po 'fuori di testa ...):

b=`echo "console.log('$a'.toLowerCase());" | node`

Potresti anche usare dd(ma io no!):

b=`echo "$a" | dd  conv=lcase 2> /dev/null`

inferiore -> SUPERIORE :

usa python:

b=`echo "print '$a'.upper()" | python`

O Ruby:

b=`echo "print '$a'.upcase" | ruby`

O Perl (probabilmente il mio preferito):

b=`perl -e "print uc('$a');"`

O PHP:

b=`php -r "print strtoupper('$a');"`

O Awk:

b=`echo "$a" | awk '{ print toupper($1) }'`

O Sed:

b=`echo "$a" | sed 's/./\U&/g'`

O Bash 4:

b=${a^^}

O NodeJS se ce l'hai (e sei un po 'fuori di testa ...):

b=`echo "console.log('$a'.toUpperCase());" | node`

Potresti anche usare dd(ma io no!):

b=`echo "$a" | dd  conv=ucase 2> /dev/null`

Anche quando dici "shell", suppongo che intendi, bashma se puoi usarlo zshè facile come

b=$a:l

per lettere minuscole e

b=$a:u

per maiuscole.


@JESii entrambi funzionano per me superiore -> inferiore e inferiore-> superiore. Sto usando sed 4.2.2 e Bash 4.3.42 (1) su Debian Stretch a 64 bit.
nettux,

1
Ciao, @ nettux443 ... Ho appena provato di nuovo l'operazione bash e non riesce ancora con il messaggio di errore "sostituzione errata". Sono su OSX usando bash di homebrew: GNU bash, versione 4.3.42 (1) -release (x86_64-apple-darwin14.5.0)
JESii

5
Non usare! Tutti gli esempi che generano uno script sono estremamente fragili; se il valore di acontiene una singola citazione, non hai solo un comportamento non corretto, ma un grave problema di sicurezza.
tripleee

Mi piace di più la soluzione sed, poiché sed è sempre onnipresente.
Dudi Boy,

Preferisco usare la soluzione dd. Nota che devi essere root per farlo funzionare
inetphantom,


18

Usando GNU sed:

sed 's/.*/\L&/'

Esempio:

$ foo="Some STRIng";
$ foo=$(echo "$foo" | sed 's/.*/\L&/')
$ echo "$foo"
some string

12

Pre Bash 4.0

Bash Abbassa il caso di una stringa e assegna a variabile

VARIABLE=$(echo "$VARIABLE" | tr '[:upper:]' '[:lower:]') 

echo "$VARIABLE"

5
Non c'è bisogno di echoe tubi: utilizzare$(tr '[:upper:]' '[:lower:]' <<<"$VARIABLE")
Tino

3
@Tino Anche la stringa qui non è portatile per tornare alle versioni davvero vecchie di Bash; Credo che sia stato introdotto nella v3.
triplo

1
@tripleee Hai ragione, è stato introdotto in bash-2.05b - tuttavia questa è la bash più antica che sono riuscita a trovare sui miei sistemi
Tino

11

Per una shell standard (senza bashismi) usando solo builtin:

uppers=ABCDEFGHIJKLMNOPQRSTUVWXYZ
lowers=abcdefghijklmnopqrstuvwxyz

lc(){ #usage: lc "SOME STRING" -> "some string"
    i=0
    while ([ $i -lt ${#1} ]) do
        CUR=${1:$i:1}
        case $uppers in
            *$CUR*)CUR=${uppers%$CUR*};OUTPUT="${OUTPUT}${lowers:${#CUR}:1}";;
            *)OUTPUT="${OUTPUT}$CUR";;
        esac
        i=$((i+1))
    done
    echo "${OUTPUT}"
}

E per le maiuscole:

uc(){ #usage: uc "some string" -> "SOME STRING"
    i=0
    while ([ $i -lt ${#1} ]) do
        CUR=${1:$i:1}
        case $lowers in
            *$CUR*)CUR=${lowers%$CUR*};OUTPUT="${OUTPUT}${uppers:${#CUR}:1}";;
            *)OUTPUT="${OUTPUT}$CUR";;
        esac
        i=$((i+1))
    done
    echo "${OUTPUT}"
}

Mi chiedo se non hai lasciato un po 'di bashismo in questo script, dato che non è portatile su FreeBSD sh: $ {1: $ ...}: Sostituzione
errata

2
Infatti; le sottostringhe con ${var:1:1}sono un bashismo.
Tripleee

Questo approccio ha metriche prestazionali piuttosto scadenti. Vedi la mia risposta per le metriche.
Dejay Clayton,

9

In bash 4 puoi usare la composizione

Esempio:

A="HELLO WORLD"
typeset -l A=$A


7

Espressione regolare

Vorrei prendere il merito per il comando che desidero condividere, ma la verità è che l'ho ottenuto per uso personale da http://commandlinefu.com . Ha il vantaggio che se si cdpassa a qualsiasi directory all'interno della propria cartella home, cambierà tutti i file e le cartelle in minuscole ricorsivamente, si prega di usare con cautela. È una brillante correzione della riga di comando e particolarmente utile per quelle moltitudini di album che hai memorizzato sul tuo disco.

find . -depth -exec rename 's/(.*)\/([^\/]*)/$1\/\L$2/' {} \;

È possibile specificare una directory al posto del punto (.) Dopo la ricerca che indica la directory corrente o il percorso completo.

Spero che questa soluzione si riveli utile, l'unica cosa che questo comando non fa è sostituire gli spazi con caratteri di sottolineatura - vabbè un'altra volta forse.


Questo non ha funzionato per me per qualsiasi motivo, anche se sembra a posto. L'ho fatto funzionare come un'alternativa però: trova. -exec / bin / bash -c 'mv {} `tr [AZ] [az] <<< {}`' \;
John Rix,

Questo ha bisogno prenamedi perl: dpkg -S "$(readlink -e /usr/bin/rename)"perl: /usr/bin/prename
Tino l'

4

Molte risposte utilizzano programmi esterni, che in realtà non stanno utilizzando Bash.

Se sai che avrai Bash4 disponibile, dovresti semplicemente usare la ${VAR,,}notazione (è facile e interessante). Per Bash prima dei 4 (il mio Mac usa ancora Bash 3.2 per esempio). Ho usato la versione corretta della risposta di @ ghostdog74 per creare una versione più portatile.

Uno che puoi chiamare lowercase 'my STRING'e ottenere una versione minuscola. Ho letto i commenti sull'impostazione del risultato su un var, ma questo non è realmente portabile in Bashquanto non possiamo restituire stringhe. La stampa è la soluzione migliore. Facile da catturare con qualcosa del genere var="$(lowercase $str)".

Come funziona

Il modo in cui funziona è ottenendo la rappresentazione intera ASCII di ciascun carattere con printfe quindi adding 32se upper-to->lower, o subtracting 32se lower-to->upper. Quindi utilizzare printfnuovamente per riconvertire il numero in un carattere. Da 'A' -to-> 'a'abbiamo una differenza di 32 caratteri.

Usando printfper spiegare:

$ printf "%d\n" "'a"
97
$ printf "%d\n" "'A"
65

97 - 65 = 32

E questa è la versione funzionante con esempi.
Nota i commenti nel codice, poiché spiegano molte cose:

#!/bin/bash

# lowerupper.sh

# Prints the lowercase version of a char
lowercaseChar(){
    case "$1" in
        [A-Z])
            n=$(printf "%d" "'$1")
            n=$((n+32))
            printf \\$(printf "%o" "$n")
            ;;
        *)
            printf "%s" "$1"
            ;;
    esac
}

# Prints the lowercase version of a sequence of strings
lowercase() {
    word="$@"
    for((i=0;i<${#word};i++)); do
        ch="${word:$i:1}"
        lowercaseChar "$ch"
    done
}

# Prints the uppercase version of a char
uppercaseChar(){
    case "$1" in
        [a-z])
            n=$(printf "%d" "'$1")
            n=$((n-32))
            printf \\$(printf "%o" "$n")
            ;;
        *)
            printf "%s" "$1"
            ;;
    esac
}

# Prints the uppercase version of a sequence of strings
uppercase() {
    word="$@"
    for((i=0;i<${#word};i++)); do
        ch="${word:$i:1}"
        uppercaseChar "$ch"
    done
}

# The functions will not add a new line, so use echo or
# append it if you want a new line after printing

# Printing stuff directly
lowercase "I AM the Walrus!"$'\n'
uppercase "I AM the Walrus!"$'\n'

echo "----------"

# Printing a var
str="A StRing WITH mixed sTUFF!"
lowercase "$str"$'\n'
uppercase "$str"$'\n'

echo "----------"

# Not quoting the var should also work, 
# since we use "$@" inside the functions
lowercase $str$'\n'
uppercase $str$'\n'

echo "----------"

# Assigning to a var
myLowerVar="$(lowercase $str)"
myUpperVar="$(uppercase $str)"
echo "myLowerVar: $myLowerVar"
echo "myUpperVar: $myUpperVar"

echo "----------"

# You can even do stuff like
if [[ 'option 2' = "$(lowercase 'OPTION 2')" ]]; then
    echo "Fine! All the same!"
else
    echo "Ops! Not the same!"
fi

exit 0

E i risultati dopo aver eseguito questo:

$ ./lowerupper.sh 
i am the walrus!
I AM THE WALRUS!
----------
a string with mixed stuff!
A STRING WITH MIXED STUFF!
----------
a string with mixed stuff!
A STRING WITH MIXED STUFF!
----------
myLowerVar: a string with mixed stuff!
myUpperVar: A STRING WITH MIXED STUFF!
----------
Fine! All the same!

Questo dovrebbe funzionare solo per i caratteri ASCII .

Per me va bene, dato che so che gli passerò solo caratteri ASCII.
Lo sto usando per alcune opzioni della CLI senza distinzione tra maiuscole e minuscole, ad esempio.


4

La conversione del caso viene eseguita solo per alfabeti. Quindi, questo dovrebbe funzionare in modo ordinato.

Mi sto concentrando sulla conversione di alfabeti da az da maiuscolo a minuscolo. Tutti gli altri personaggi dovrebbero essere stampati in stdout così com'è ...

Converte tutto il testo nel percorso / in / file / nomefile nell'intervallo az in AZ

Per convertire lettere minuscole in maiuscole

cat path/to/file/filename | tr 'a-z' 'A-Z'

Per la conversione da lettere maiuscole a lettere minuscole

cat path/to/file/filename | tr 'A-Z' 'a-z'

Per esempio,

nome del file:

my name is xyz

viene convertito in:

MY NAME IS XYZ

Esempio 2:

echo "my name is 123 karthik" | tr 'a-z' 'A-Z'
# Output:
# MY NAME IS 123 KARTHIK

Esempio 3:

echo "my name is 123 &&^&& #@$#@%%& kAR2~thik" | tr 'a-z' 'A-Z'
# Output:
# MY NAME IS 123 &&^&& #@0@%%& KAR2~THIK

3

Se si utilizza v4, questo è cotto . In caso contrario, ecco una soluzione semplice e ampiamente applicabile . Altre risposte (e commenti) su questo thread sono state molto utili nella creazione del codice seguente.

# Like echo, but converts to lowercase
echolcase () {
    tr [:upper:] [:lower:] <<< "${*}"
}

# Takes one arg by reference (var name) and makes it lowercase
lcase () { 
    eval "${1}"=\'$(echo ${!1//\'/"'\''"} | tr [:upper:] [:lower:] )\'
}

Appunti:

  • Fare: a="Hi All"e poi: lcase afarà la stessa cosa di:a=$( echolcase "Hi All" )
  • Nella funzione lcase, l'utilizzo ${!1//\'/"'\''"}invece di ${!1}consente a questo di funzionare anche quando la stringa ha virgolette.

3

Per le versioni di Bash precedenti alla 4.0, questa versione dovrebbe essere la più veloce (poiché non esegue il fork / exec di alcun comando):

function string.monolithic.tolower
{
   local __word=$1
   local __len=${#__word}
   local __char
   local __octal
   local __decimal
   local __result

   for (( i=0; i<__len; i++ ))
   do
      __char=${__word:$i:1}
      case "$__char" in
         [A-Z] )
            printf -v __decimal '%d' "'$__char"
            printf -v __octal '%03o' $(( $__decimal ^ 0x20 ))
            printf -v __char \\$__octal
            ;;
      esac
      __result+="$__char"
   done
   REPLY="$__result"
}

Anche la risposta di technosaurus aveva un potenziale, sebbene funzionasse correttamente per me.


Non male! Per un'analisi delle prestazioni di questo approccio, consultare la mia risposta per le metriche.
Dejay Clayton,

3

Nonostante quanti anni questa domanda sia simile a questa risposta del technosaurus . Ho avuto difficoltà a trovare una soluzione portatile su gran parte delle piattaforme (That I Use) e versioni precedenti di bash. Sono stato anche frustrato dalle matrici, dalle funzioni e dall'uso di stampe, echi e file temporanei per recuperare variabili insignificanti. Questo funziona molto bene per me finora ho pensato di condividere. I miei principali ambienti di test sono:

  1. GNU bash, versione 4.1.2 (1) -release (x86_64-redhat-linux-gnu)
  2. GNU bash, versione 3.2.57 (1) -release (sparc-sun-solaris2.10)
lcs="abcdefghijklmnopqrstuvwxyz"
ucs="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
input="Change Me To All Capitals"
for (( i=0; i<"${#input}"; i++ )) ; do :
    for (( j=0; j<"${#lcs}"; j++ )) ; do :
        if [[ "${input:$i:1}" == "${lcs:$j:1}" ]] ; then
            input="${input/${input:$i:1}/${ucs:$j:1}}" 
        fi
    done
done

Semplice stile C per il loop per scorrere le stringhe. Per la riga qui sotto se non hai visto nulla di simile prima di questo è dove ho imparato questo . In questo caso la riga controlla se il carattere $ {input: $ i: 1} (minuscolo) esiste nell'input e in tal caso lo sostituisce con il carattere $ $ {ucs: $ j: 1} (maiuscolo) e lo memorizza di nuovo in input.

input="${input/${input:$i:1}/${ucs:$j:1}}"

Questo è estremamente inefficiente, eseguendo il loop 650 volte nell'esempio sopra riportato e impiegando 35 secondi per eseguire 1000 invocazioni sulla mia macchina. Per un'alternativa che gira solo 11 volte e impiega meno di 5 secondi per eseguire 1000 invocazioni, vedi la mia risposta alternativa.
Dejay Clayton,

1
Grazie, anche se dovrebbe essere ovvio solo dal guardarlo. Forse gli errori di pagina provengono dalla dimensione di input e dal numero di iterazioni che si stanno eseguendo. Tuttavia mi piace la tua soluzione.
JaredTS486,

3

Questa è una variante molto più veloce dell'approccio di JaredTS486 che utilizza le funzionalità native di Bash (comprese le versioni di Bash <4.0) per ottimizzare il suo approccio.

Ho cronometrato 1.000 iterazioni di questo approccio per una stringa piccola (25 caratteri) e una stringa più grande (445 caratteri), sia per le conversioni minuscole che maiuscole. Poiché le stringhe di test sono prevalentemente minuscole, le conversioni in minuscolo sono generalmente più veloci che in maiuscolo.

Ho confrontato il mio approccio con molte altre risposte in questa pagina che sono compatibili con Bash 3.2. Il mio approccio è molto più performante della maggior parte degli approcci documentati qui ed è persino più veloce che trin molti casi.

Ecco i risultati di temporizzazione per 1.000 iterazioni di 25 caratteri:

  • 0.46s per il mio approccio al minuscolo; 0.96s per maiuscole
  • 1.16s per l'approccio di Orwellophile alle lettere minuscole; 1.59s per maiuscole
  • 3.67s per trminuscole; 3.81s per maiuscole
  • 11.12s per l'approccio di ghostdog74 alle lettere minuscole; 31.41s per maiuscole
  • 26,25 per l'approccio del technosaurus al minuscolo; 26.21s per maiuscole
  • 25.06 per l'approccio di JaredTS486 alle lettere minuscole; 27.04s per maiuscole

Risultati temporali per 1.000 iterazioni di 445 caratteri (costituito dal poema "The Robin" di Witter Bynner):

  • 2s per il mio approccio al minuscolo; 12s per maiuscole
  • 4s per trminuscole; 4s per le maiuscole
  • 20s per l'approccio di Orwellophile alle lettere minuscole; 29s per maiuscole
  • 75s per l' approccio di ghostdog74 al minuscolo; 669 per maiuscole. È interessante notare quanto sia drammatica la differenza prestazionale tra un test con partite predominanti e un test con mancanze predominanti
  • 467s per l'approccio di technosaurus al minuscolo; 449s per maiuscole
  • 660s per l'approccio di JaredTS486 al minuscolo; 660 per maiuscole. È interessante notare che questo approccio ha generato errori di pagina continui (scambio di memoria) in Bash

Soluzione:

#!/bin/bash
set -e
set -u

declare LCS="abcdefghijklmnopqrstuvwxyz"
declare UCS="ABCDEFGHIJKLMNOPQRSTUVWXYZ"

function lcase()
{
  local TARGET="${1-}"
  local UCHAR=''
  local UOFFSET=''

  while [[ "${TARGET}" =~ ([A-Z]) ]]
  do
    UCHAR="${BASH_REMATCH[1]}"
    UOFFSET="${UCS%%${UCHAR}*}"
    TARGET="${TARGET//${UCHAR}/${LCS:${#UOFFSET}:1}}"
  done

  echo -n "${TARGET}"
}

function ucase()
{
  local TARGET="${1-}"
  local LCHAR=''
  local LOFFSET=''

  while [[ "${TARGET}" =~ ([a-z]) ]]
  do
    LCHAR="${BASH_REMATCH[1]}"
    LOFFSET="${LCS%%${LCHAR}*}"
    TARGET="${TARGET//${LCHAR}/${UCS:${#LOFFSET}:1}}"
  done

  echo -n "${TARGET}"
}

L'approccio è semplice: mentre nella stringa di input sono presenti lettere maiuscole rimanenti, trova la successiva e sostituisci tutte le istanze di quella lettera con la sua variante minuscola. Ripetere fino a quando tutte le lettere maiuscole non vengono sostituite.

Alcune caratteristiche prestazionali della mia soluzione:

  1. Utilizza solo utility integrate nella shell, che evitano il sovraccarico di invocare utility binarie esterne in un nuovo processo
  2. Evita i sub-shell, che comportano penalità di prestazione
  3. Utilizza meccanismi di shell che sono compilati e ottimizzati per le prestazioni, come la sostituzione globale delle stringhe all'interno delle variabili, il taglio del suffisso variabile e la ricerca e la corrispondenza di regex. Questi meccanismi sono molto più veloci rispetto all'iterazione manuale delle stringhe
  4. Ripete solo il numero di volte richiesto dal conteggio dei caratteri di corrispondenza univoci da convertire. Ad esempio, la conversione di una stringa con tre diversi caratteri maiuscoli in minuscole richiede solo 3 iterazioni in loop. Per l'alfabeto ASCII preconfigurato, il numero massimo di iterazioni di loop è 26
  5. UCSe LCSpuò essere aumentato con caratteri aggiuntivi

2

Per memorizzare la stringa trasformata in una variabile. Seguito ha funzionato per me - $SOURCE_NAMEa$TARGET_NAME

TARGET_NAME="`echo $SOURCE_NAME | tr '[:upper:]' '[:lower:]'`"

1

Modo semplice

echo "Hi all" | awk '{ print tolower($0); }'
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.