JavaScript (ES6), 49 bytes
s=>s.replace(/[beis]/gi,c=>parseInt(c+1,31)%9||8)
Try it online!
How?
By using parseInt()
, we don't have to worry about the case at all since lowercase and uppercase letters are parsed the same way. The downside of this formula is that we have to explicitly turn \$0\$ into \$8\$. It's still 1 byte shorter than the Node version, though.
char | +'1' | base 31 -> decimal | mod 9 | || 8
------+------+--------------------+-------+------
'b' | 'b1' | 342 | 0 | 8
'e' | 'e1' | 435 | 3 | 3
'i' | 'i1' | 559 | 1 | 1
's' | 's1' | 869 | 5 | 5
s=>s.replace(/[beis]/gi,c=>17/(Buffer(c)[0]%16)|0)
Try it online!
How?
We look for beis
in the input string in a case-insensitive way. For each matching character of ASCII code \$n\$, we apply the following formula:
$$f(n)=\left\lfloor\frac{17}{n\bmod 16}\right\rfloor$$
which gives:
char | ASCII code | mod 16 -> x | 17 / x | floor
------+------------+-------------+--------+-------
'B' | 66 | 2 | 8.5 | 8
'b' | 98 | 2 | 8.5 | 8
'E' | 69 | 5 | 3.4 | 3
'e' | 101 | 5 | 3.4 | 3
'I' | 73 | 9 | 1.889 | 1
'i' | 105 | 9 | 1.889 | 1
'S' | 83 | 3 | 5.667 | 5
's' | 115 | 3 | 5.667 | 5
NB: we could use \$16\$ instead of \$17\$ just as well.
code-golf
from the beginning. \$\endgroup\$i
. \$\endgroup\$