10

I am trying to write a code that would turn any given word to its numeronym.

for example : internationalization = i18n (first char+number of chars in between+last char)

I found how to find the first and the last character and I know how to find the number part, but I don't know how to put the number between the first and the last character.

The code I used to get the number part is:

cut -c 2- | rev | cut -c 2- | rev | tr -d [:space:]| wc -c 

The code I used to get the first and the last chacarters:

awk -F "" '{print $1,$NF}'
3
  • 7
    Do a, an, or the have numeronyms?
    – Jeff Schaller
    Oct 24, 2019 at 14:17
  • 6
    @JeffSchaller. a, an, t1e Oct 25, 2019 at 16:59
  • 7
    Ah, the time saving "t1e" shortcut. Oct 26, 2019 at 22:27

4 Answers 4

18

Although I find the use of awk with an empty field separator somewhat 'innovative', the simplest solution in my opinion is just a small expansion of yours:

awk -F "" '{print $1 (NF-2) $NF}'

This works only with words of three or more letters, of course. To handle the general case:

awk -F "" '{if (NF>2) print $1 (NF-2) $NF; else print $0}'

As an explanation:

  • By setting the field separator to "empty" with -F "", the input is split into fields after every character, i.e. every character of the input is considered an individual "field" that is accessible via $n in awk expressions (with n being the field number ranging from 1 to NF). Btw, the GNU Awk User's Guide explicitly provides such use cases as examples, so I stand corrected on my previous concerns about using an empty FS. Still, note that the manual says "This is a common extension; it is not specified by the POSIX standard".
  • if the number of fields (i.e. characters, here) is larger than two, print the first field/character ($1), the evaluated expression (NF-2) which amounts to the number of characters in between the first and the last, and the last field/character ($NF). Note that the print call as used here does not produce space between the individual output tokens; this only happens when separating the arguments with commas instead of space (see e.g. the GNU Awk User's Guide).
  • else simply print the entire input expression, which is accessible via $0

Note that if we fould feed a two-character input, e.g. at, to the first code example, we would get unwanted (but formally correct) output like a0t (because there are, in this case, zero characters between first and last).

Note also, and this is important, that if you supply a string containing leading or trailing whitespace to this awk call, like in echo " hello" | awk <etc.>, then that leading/trailing whitespace would be treated as the first/last character, thus giving unwanted behaviour!

3
  • The empty-field-separator trick does not work with BSD's version of awk. Oct 25, 2019 at 8:21
  • Yes, I expected that something like this might happen, and that is why I quoted the warning notice from the GNU Awk manual. However, since the OP had success with this approach, I considered it safe to assume that at least he is working with GNU awk or compatible ...
    – AdminBee
    Oct 25, 2019 at 11:07
  • 2
    You can actually even use the fact that awk prints $0 as default action, = returns the assigned value and no numeronym is empty (i.e. zero/false) to shorten the whole thing to awk -F '' '$0=$1NF-2$NF'
    – mschilli
    Oct 25, 2019 at 13:24
15

In ksh93, bash or zsh:

numeronym() {
  (( ${#1} > 2 )) || return
  printf '%s%d%s\n' "${1:0:1}" "$(( ${#1} - 2 ))" "${1: -1:1}"
}

This works on the first (only) parameter by printing the first letter, (number of characters minus 2), and last letter.

10

Another awk solution:

awk '{l=length($1); print substr($1,1,1) l-2 substr($1,l,1)}'
  • l=length($1) - Set the l variable to the length of your string (Assuming the input string is in the first column and does not contain whitespace)
  • substr($1,1,1) - (column #, starting point, ending point) so print column 1, starting at position 1, and print 1 character.
  • l-2 - Length of string minus 2
  • substr($1,l,1) - Print column 1 starting at position l (length of string) and print 1 character.
5
  • Could you explain the code please. I am just learning awk, so i don't know the substr part.
    – arty
    Oct 24, 2019 at 14:36
  • 1
    @arthionne: sure I have added explainations however I think AdminBee's answer is better than mine. I would suggest accepting that answer.
    – jesse_b
    Oct 24, 2019 at 14:40
  • 1
    @Jesse_b funny, I just upvoted your answer (I'm just not too sure about this "empty field separator" thing ...)
    – AdminBee
    Oct 24, 2019 at 14:41
  • Thanks for the explanation!
    – arty
    Oct 24, 2019 at 15:10
  • 1
    You may want to choose a different variable for your example: 1 and l are a bit difficult to distinguish. Oct 25, 2019 at 19:51
5

Portable to many shells:

a=internationalization;
if [ "${#a}" -gt 2 ]; then 
    a="${a%"${a#?}"}$((${#a}-2))${a#"${a%?}"}";
fi
printf '%s\n' "${a}"

As a function (sligtly less portable):

numeronym() {  a="$1";
               if [ "${#1}" -gt 2 ]; then 
                    a="${a%"${a#?}"}$((${#a}-2))${a#"${a%?}"}";
               fi;
               printf '%s\n' "${a}";
            }

Call it as:

$ numeronym internationalization
i18n

If it must be awk:

$ echo internationalization |
      awk '{ print (NF>2) ? $1 NF-2 $NF : $0 }' FS=''

i18n

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.