g | x | w | all
Bytes Lang Time Link
125sed r240612T210457ZJan Blum
234Bash240610T103004ZThemooni
05205AB1E240610T082935ZKevin Cr
176Python240608T200802ZNicola S
138JavaScript ES6240608T142542ZArnauld
082Charcoal240608T225309ZNeil
092Retina 0.8.2240608T151253ZNeil

sed -r, 125 bytes

Expecting all-uppercase input

s/ (..? \w+|\S+)$/_&/
s/\W//g
:1
s/([AEIOU])([^AEIOU_])/\2\1/
t1
/^[^AEIOU_]{4}/s/(.)./\1/
s/_.*/X&X/
s/(...).*_(...).*/\2\1/

Try it online!

sed -r, 135 bytes

Variant that accepts input in either case

s/./\U&/g
s/ (..? \w+|\S+)$/_&/
s/\W//g
:1
s/([AEIOU])([^AEIOU_])/\2\1/
t1
/^[^AEIOU_]{4}/s/(.)./\1/
s/_.*/X&X/
s/(...).*_(...).*/\2\1/

Try it online!

Bash, 234 bytes

s=${@: -2:1}
l=${@: -1}
u=1
(($#>2&&`wc -m<<<$s`<4&&`grep -c [\'-]<<<$l`<1))&&l=$s$l&&u=2
f=${@:1:(($#-$u))}
v="[aeiou '-]"
p=[!aeiou]
c=${f//$v}
((`wc -m<<<$c`>4))&&c=${c:0:1}${c:2}
head -c3<<<${l//$v}${l//$p}x
head -c3<<<$c${f//$p}x

Attempt This Online!

🏆: broke syntax highlighting

Call as a bash function or script, with the name as arguments in lowercase. You may need to escape 's as otherwise bash will try parsing a string.
ATO link has automatic lowercase conversion for your convenience.

thanks to @GammaFunction for his entry into a previous challenge that helped me separate consonnants and vowels.

explanation:

# implicit: bash automatically separates arguments by whitespace, so calling `script a b c` is equivalent to calling script(a, b, c) in other languages
s=${@: -2:1}     # set s to the (s)econd to last argument
l=${@: -1}       # set l to the (l)ast argument
u=1              # u counts the numer of arguments that make up the last name, 1 by default
  $#>2           # there are more than 2 arguments
        `wc -m<<<$s`<4     # the second to last argument has 2 characters or less (wc counts a trailing char, and < is shorter than <=, so we use 4 instead of 2)
                        `grep -c [\'-]<<<$l`<1  # the last argument has no `'` or `-`
((    &&              &&                      ))  # if the 3 last expressions are all true...
                                                &&l=$s$l&&u=2 # then concatenate the last 2 arguments, making the last name, and set u to 2
f=${@:1:(($#-$u))} # set f to all arguments until u, making the (f)irst name
v="[aeiou '-]" #store a regular expression for later
p=[!aeiou]     #store another regular expression
c=${f//$v}     #set c to the (c)onsonnants in the first name, using the first regex.
((`wc -m<<<$c`>4))  #if there are more than 3 of them...
                  &&c=${c:0:1}${c:2}  #set c to c[0]+c[2:], skipping the second consonnant
           ${l//$v}${l//$p}x   #concat consonnants and vowels in the last name, and an additionnal x
head -c3<<<                    #trim the previous to 3 characters and output to stdout
head -c3<<<$c${f//$p}x         #do the same to the first name, but using $c, which may have the second consonnant missing

05AB1E, 53 52 bytes

#R©¬a®g3@®1èg3‹**>®g‚£íðýlεáΣžMså}ÀDžNÃg4@N*.$Á'x«3£

Outputs as a lowercase pair of 3-char strings.

Try it online or verify all test cases.

Explanation:

Step 1: Split the input into first name and surname:

#               # Split the (implicit) input-string on spaces
 R              # Reverse this list
  ©             # Store it in variable `®` (without popping)
   ¬            # Push its first item (without popping the list)
    a           # Check if it's alphabetic (aka doesn't contain any "'-"-chars)
   ®            # Push list `®` again
    g           # Pop and push the length of this list
     3@         # Check if this list-length is >=3
   ®            # Push list `®` yet again
    1è          # Pop and leave just its second item
      g         # Pop and push the length of this string
       3‹       # Check if this string-length is <3
   **           # Combine all three checks
     >          # Increment this 0 or 1 to 1 or 2
      ®g        # Push the length of list `®` again
        ‚       # Pair the two together
         £      # Split the list into parts of those sizes
          í     # Reverse each inner list
           ðý   # Join each inner list with space delimiter

Try just step 1 online.

Step 2: Convert the surname and first name to the three letter Codice fiscale portions, and output the resulting pair:

l               # Convert everything to lowercase
 ε              # Map over the pair with surname and first name:
  á             #  Only leave the letters, removing " '-"-characters
   Σ            #  Sort these letters by:
    žM          #   Push the vowels(-y) constant string: "aeiou"
      s         #   Swap so the current letter is at the top
       å        #   Check if it's in this string
   }À           #  After the sort: rotate the string once towards the left
     D          #  Duplicate this string
      žNÃ       #  Only keep all consonants(+y) of this copy
         g      #  Pop and push the length of this consonants-string
          4@    #  Check if this consonants-length is >=4
            N*  #  Multiply it by the 0-based map-index
     .$         #  Remove that many leading characters
       Á        #  Rotate the string back once towards the right
        'x«    '#  Append "x"
           3£   #  Pop and keep the first three characters
                # (after which the result is output implicitly)

Python, 176 bytes

lambda F,K=lambda S,b="[\W":sub(b+"AEIOU]","",S):[(sub(f"(.){Q}.)",r"\1\2",K(P))+K(P,"[^")+"X")[:3]for P,Q in zip(split(" (.. ?\w+|\S+)$",F),[".(.","("])][::-1]
from re import*

Attempt This Online!

Expects uppercase input. Outputs a list of two strings: surname, then name.

Based on my previous answer (below) but treats name and surname in a loop rather than explicitly.

Indebted to Arnauld for the name/surname regexp / (.. ?\w+|\S+)$/. The "4 letters, skip the second" regexp /(.).(..)/ is also used by Neil.


Previous (with explanation):

Python, 180 bytes

from re import*
K=lambda S,b=0:sub("[[\^W"[b::2]+"AEIOU]","",S)+"X"*b
def f(F):
 n,s,_=split(" (.. ?\w+|\S+)$",F)
 return(K(s)+K(s,1))[:3]+(sub("(.).(..)",r"\1\2",K(n))+K(n,1))[:3]

Attempt This Online!

Expects uppercase input.

Explanation

from re import*                     # We will be using regexps.

K=lambda S,b=0:                     # Utility function. Takes a string and a 0/1 flag.
  sub("[[\^W"[b::2]+"AEIOU]","",S)  # If b=0, deletes vowels and symbols ([\WAEIOU]).
                                    # If b=1, deletes everything except vowels ([^AIEOU]).
  +"X"*b                            # If b=1, it also adds a "X".

def f(F):
 n,s,_=split(" (.. ?\w+|\S+)$",F)   # Arnauld's regexp splits name (n) and surname (s).
 return(K(s)+K(s,1)                 # Call K() on s, first for consonants (b=0), then for
                                    #  vowels and trailing "X" (b=1), and...
                   )[:3]            #  keep 3 chars.
  +(                                # Same for n, but, ...
    sub("(.).(..)",r"\1\2",K(n))    #  if K(n,0) contains any seq of 4 chars ("(X)Y(ZW)"),
                                    #  keep only the two groups in parentheses: "XZW".
    +K(n,1))[:3]

PS

Answering my own question (which is allowed, although waiting some time is advised). I only waited 8 hours because I didn't really get a head start (thought about this problem this morning), and I'm less proficient than other Python golfers so I don't believe this is going to be a winning Python entry.

In particular, I liked the regexp-based answers that have been posted so I wanted to try my own.

JavaScript (ES6), 138 bytes

Expects the input in lowercase and returns a string in lowercase as well.

s=>(g=r=>(s.split(/ (.. ?\w+|\S+)$/)[+!r].replace(/[aeiou\W]/g,c=>(c>{}?v+=c:0,""),v="").replace(r,"")+v+"x").slice(0,3))()+g(/\B.(?=..)/)

Try it online!

Commented

s => (                  // s = input string
  g = r => (            // g is a helper function taking a regex r
    s.split(            // split the original string ...
      / (.. ?\w+|\S+)$/ // ... using a regex that matches the surname
    )[+!r]              // keep the name if r is defined,
                        // or the surname otherwise
    .replace(           // replace:
      /[aeiou\W]/g,     //   match all vowels and non-letter characters
      c => (            //   for each matched character c:
        c > {} ?        //     if c is a letter (i.e. a vowel):
          v += c        //       append it to v
        :               //     else:
          0,            //       do nothing
        ""              //     always remove the original character
      ),                //
      v = ""            //   start with v = "" (string of vowels)
    )                   // end of replace() -> only consonants remain
    .replace(r, "") +   // apply the regex r to conditionally remove
                        // the second consonant (for the name only)
    v + "x"             // append the vowels and a trailing "x"
  ).slice(0, 3)         // keep the first 3 characters
)() +                   // 1st call to g for the surname with no regex
g(                      // 2nd call to g for the name with a regex that
  /\B.(?=..)/           // matches the 2nd character if the 4th one is
)                       // defined

Charcoal, 82 bytes

≔AEIOUθ≔⪪S η≔⟦⪫⮌E⊕∧⬤§η±¹№αι›³L§η±²⊟ηω⪫ηω⟧ηUMη⭆²Φι∧№αν⁼λ№θν⭆η…⁺Φι∨¬κ∨⊖μ№θ§⁺§η¹AA³X³

Try it online! Link is to verbose version of code. Takes input in upper case (could take in mixed case at a cost of a byte). Explanation:

≔AEIOUθ

Get the vowels in a variable as this saves a byte.

≔⪪S η

Input the name and split it on spaces.

≔⟦⪫⮌E⊕∧⬤§η±¹№αι›³L§η±²⊟ηω⪫ηω⟧η

Extract the surname and given name.

UMη⭆²Φι∧№αν⁼λ№θν

For each name, sort the consonants to the start and the vowels to the end and ignore other characters.

⭆η…⁺Φι∨¬κ∨⊖μ№θ§⁺§η¹AA³X³

Remove the second consonant of four in the given name, then take the first three letters of each name, filling with X if necessary.

Retina 0.8.2, 94 92 bytes

(.+?) (..? \w+|\S+)$
$2¶$1
%`\W

%O$`([AEIOU])|.
$.1
(¶.).(.[^AEIOU])
$1$2
%`$
X
%M!`^...
¶

Try it online! Takes input in upper case but link is to test suite that uppercases input. Explanation:

(.+?) (..? \w+|\S+)$
$2¶$1

Extract the surname and given name. (Note: this assumes that there won't be two spaces in a row.)

%`\W

Remove all non-letters, but on each name separately, so that the newline doesn't get removed.

%O$`([AEIOU])|.
$.1

Sort the vowels to the end on each name separately.

(¶.).(.[^AEIOU])
$1$2

Remove the second consonant of the given name if there are at least four.

%`$
X
%M!`^...

For each name, take the first three letters, filling in with an X if there are only two.

Join the codes of the surname and given name together.

Edit: Saved 2 bytes thanks to @Arnauld.