Я знаю, что это годы спустя, но почему бы не пойти так:
$dom='a.b.c.d.co.jp';
$sub=preg_replace("/.*?([^\.]+)(\.((co\.\w+)|\w+))$/i",'\1\2',$dom); //strip subdomains
это печатает d.co.jp
, где .*?([^\.]+)(\.((co\.\w+)|\w+))$
будет означать:
.*?
Ленивый (поэтому он не захватывает основной домен) соответствует всем символам до тех пор, пока не последует
([^\.]+)
соответствует группе символов, которые не содержат точку (т. Е. Основной домен или домен следующего сверху) ( + , обеспечивающий наличие хотя бы один символ класса) и верните его позже \ 1
(\.((co\.\w+)|\w+))
сопоставить TLD с предыдущей точкой, будь то .co. что-то или . что-то и вернуть через \ 2 ; знак плюс делает то же самое здесь
$
привязать все к концу строки, чтобы мы могли пройти весь путь от TLD влево до частей поддоменов, независимо от их количества
P.S. Я не знаю, есть ли другие TLD, состоящие из двух частей, но они также могут быть добавлены. Быстрый пробежка по https://en.wikipedia.org/wiki/List_of_Internet_top-level_domains говорит мне, что нет, но если они есть, я думаю, что они не так уж и велики.