Обучение компьютера русскому

У меня на работе пользователям присылалось автоматическое уведомление о кончающемся сроке действия их пароля, где первой строкой была фраза:

Уважаемый пользователь Информационных Систем!

Проблема хорошо описана в статье «Здравствуйте, с вами говорит робот», и мне хотелось очеловечить эти формальные уведомления, например, чтобы первой строкой было обращение по имени и отчеству с соответствующим изменением окончания слова «уважаемый» в зависимости от пола адресата.

Желание решить такую задачу заставляет задуматься о логике родного языка. Считается, что очень логичный язык английский, а в русском всё устроено не пойми как — порядок слов какой хочешь, окончания меняются и так далее. Тем не менее, любой язык логичен, просто большинство использует его интуитивно и не задумывается о принципах функционирования, особенно после окончания школы. Я не исключение, но так как задача требует перевести принципы русского языка на язык, понятный компьютеру, то постигнуть эту логику необходимо и мне, но уже самостоятельно.

Первым делом нужно понять, как отделять мужские ФИО от женских. Просматривая списки, я обнаружил, что ключом к разгадке являются отчества — все мужские отчества заканчиваются на «ич», а все женские — на «на». Сначала я думал, что одинаковы три последних буквы, но, например, у мужчин есть Ильич и Кузьмич, а у женщин Ильинична и Кузьминична, так что остановился на двух.

Так-то лучше:

# Выборка
if ($user.givenname -match "на$") {$body1 = "Уважаемая $($user.givenname)!"}
elseif ($user.givenname -match "ич$") {$body1 = "Уважаемый $($user.givenname)!"}
# А случаи бывают разные
elseif (!($user.givenname)) {$body1 = "Уважаемый $($user.name)!"}
else {$body1 = "Уважаемый пользователь информационных систем АО «Мир шерстяных носков»!"}
# Результат
$body1

Уважаемый Игорь Валерианович!
Уважаемый Михаил Сергеевич!
Уважаемый Игорь Алексеевич!
Уважаемая Олеся Андреевна!
Уважаемая Анна Васильевна!
Уважаемая Светлана Николаевна!
Уважаемый Алексей Владимирович!
Уважаемый Сергей Владимирович!
Уважаемая Любовь Владимировна!
Уважаемая Полина Евгеньевна!

Следующий этап — зависимость окончания слова «день» от их количества. Надо составить фразу «Действие вашего пароля истекает через N дней». Путём нехитрых размышлений получается, что вроде бы все числа, заканчивающиеся на 1 — это «день», на 2,3 и 4 — «дня», а все остальные — «дней». Проверяем:

if ($user.daystoexp -match "1$") {$in = "через $($user.daystoexp) день"}
elseif ($user.daystoexp -match "[234]$") {$in = "через $($user.daystoexp) дня"}
else {$in = "через $($user.daystoexp) дней"}
# Результат
"Действие вашего пароля истекает $in."

Действие вашего пароля истекает через 24 дня.
Действие вашего пароля истекает через 17 дней.
Действие вашего пароля истекает через 14 дня. # !
Действие вашего пароля истекает через 2 дня.
Действие вашего пароля истекает через 49 дней.
Действие вашего пароля истекает через 23 дня.
Действие вашего пароля истекает через 55 дней.
Действие вашего пароля истекает через 12 дня. # !
Действие вашего пароля истекает через 1 день.
Действие вашего пароля истекает через 11 день. # !

Русский язык велик и могуч, его с кондачка не возьмёшь! Исключение — числа с одиннадцати до четырнадцати: они все должны заканчиваться словом «дней», причём, в любой сотне — «через 11, 112, 1513, 614 дней». Исправляем:

if ($user.daystoexp -match "(?<!1)1$") {$in = "через $($user.daystoexp) день"}
elseif ($user.daystoexp -match "(?<!1)[234]$") {$in = "через $($user.daystoexp) дня"}
else {$in = "через $($user.daystoexp) дней"}
# Результат
"Действие вашего пароля истекает $in."

Действие вашего пароля истекает через 24 дня.
Действие вашего пароля истекает через 17 дней.
Действие вашего пароля истекает через 14 дней.
Действие вашего пароля истекает через 2 дня.
Действие вашего пароля истекает через 49 дней.
Действие вашего пароля истекает через 23 дня.
Действие вашего пароля истекает через 55 дней.
Действие вашего пароля истекает через 12 дней.
Действие вашего пароля истекает через 1 день.
Действие вашего пароля истекает через 11 дней.

Так-то лучше! Теперь бездушный компьютер будет обращаться к людям по имени-отчеству, да ещё и правильно склоняя слова, что, по-моему, отлично.

Напоследок расскажу, что, оказывается, дата истечения срока действия пароля вычисляется самим контроллером домена и хранится в атрибуте msDS-UserPasswordExpiryTimeComputed, причём, в нечитаемом формате FileTime (количество 100-наносекундных интервалов с 1 января 1601 г.). Чтобы преобразовать это значение в «нормальный» формат при запросе, нужно написать что-то вроде

Get-ADUser username -Properties msDS-UserPasswordExpiryTimeComputed |
select name,samaccountname,@{n='passexpdate';e={[datetime]::FromFileTime($_.'msDS-UserPasswordExpiryTimeComputed')}}

У нас в домене нет Fine-Grained Password Policies (FGPP), так что при их наличии значение этого параметра надо проверять.