poprawna-forma-liczby-mnogiej-php

Jak wyświetlać poprawną formę rzeczowników liczby mnogiej w PHP

POPRAWIONE ROZWIĄZANIE:

$plural_matches = [
    'osoba' => ['1'],
    'osób' => ['*0', '*1', '*5', '*6', '*7', '*8', '*9'],
    'osoby' => ['*2', '*3', '*4']
];

$number = (string) rand(0, 999999);
$last_digit = substr($number, -1);
// wyjątek dla '1'
$look_for = strlen($number) == $last_digit && $last_digit == 1 ? '1' : "*$last_digit";
function findVariant($plural_matches, $look_for) {
    foreach ($plural_matches as $key=>$variants) {
        if (in_array($look_for, $variants)) {
            return $key;
        }
    }
    return false;
}
echo "$number ".findVariant($plural_matches, $look_for);

Tak to już w pracy programisty bywa, że oprócz reguł rządzących językami programowania, musi często uważać także na zawiłe aspekty naszego ojczystego języka mówionego. Chyba nie polskiego kodera, który wcześniej czy później nie trafi na problem poprawnego użycia liczby mnogiej.

Chodzi o to, że w języku polskim rzeczowniki w liczbie mnogiej przyjmują różne końcówki w zalezności od danej liczby. Dla przykładu, tak to wygląda w przypadku rzeczownika „osoby”:

2 osoby
5 osób
22 osoby
23 osoby
24 osoby
25 osób
...
101 osób
102 osoby
...
1239 osób
...
1302 osoby
...
907342034 osoby
907342035 osoby

W poniższym tutorialu zademonstruję, jak rozwiązać ten problem, czyli jak wyświetlać poprawną formę „osoby” w zależności od liczby osób.

Najpierw przeanalizujmy, jak zmienia się forma „osób/osoby„. Szybko zauważymy, że forma rzeczownika zależy od ostatniej cyfry liczebnika – bez względu, z jak dużym liczebnikiem mamy do czynienia. I tak, dla liczb kończących się na 2,3 oraz 4, mamy formę „osoby”, np:

8**2** osoby
16**3** osoby
902**4** osoby

… a dla liczb kończących się pozostałymi cyframi, mamy formę „osób„:

80 osób
81 osób
165 osób
9026 osób
4897 osób
...itd.

W takim razie wystarczy nam tylko dowiedzieć się, jaka jest ostatnia cyfra naszej liczby osób. Aby to zrobić, skorzystamy z funkcji SUBSTR.

$liczba_osob = 124; // to tylko przykład, możesz zadeklarować dowolną wartość całkowitą
$ostatnia_cyfra = substr($liczba_osob, -1);

Następnie użyjemy prostej instrukcji warunkowej, aby wyświetlić odpowiednią formę „osoby”:

if ($ostatnia_cyfra == 2 OR $ostatnia_cyfra == 3 or $ostatnia_cyfra == 4): 
    echo $liczba_osob." osoby";
else:
    echo $liczba_osob." osób";
endif;

Cały kod wygląda więc tak:

$liczba_osob = 124; // to tylko przykład, możesz zadeklarować dowolną wartość całkowitą
$ostatnia_cyfra = substr($liczba_osob, -1);
if ($ostatnia_cyfra == 2 OR $ostatnia_cyfra == 3 or $ostatnia_cyfra == 4): 
    echo $liczba_osob." osoby";
else:
    echo $liczba_osob." osób";
endif;

Testując nasz kod przez podawanie różnych zmienny dla $liczba_osób (122, 123, 124, 125) widzimy, że sprawdza się doskonale i wyświetla odpowiednio 122 osoby, 123 osoby, 124 osoby, 125 osób. Niestety, nie jest to jeszcze 100-procentowe rozwiązanie. Nasze początkowe założenie, że poprawna forma rzeczownika w języku polskim zależy od ostatniej cyfry liczebnika jest nie do końca słuszne, a mianowicie nie sprawdza się w przypadku liczb 12, 13 oraz 14. W tych przypadkach bowiem poprawna forma to „osób„, a nasz aktualny kod wyrzuci oczywiście „osoby„, ponieważ liczby te kończą się cyframi podanymi przez nas w warunku.

Aby rozwiązać ten problem, musimy rozszerzyć naszą instrukcję warunkową:

if (($liczba_osob != 12 AND $liczba_osob != 13 AND $liczba_osob != 14) AND ($ostatnia_cyfra == 2 OR $ostatnia_cyfra == 3 or $ostatnia_cyfra == 4)):
    echo $liczba_osob." osoby";
else:
    echo $liczba_osob." osób";
endif;

W ten sposób nasz skrypt, zanim wyświetli „osoby” sprawdza 2 główne warunki – po pierwsze, $liczba_osób musi być różna od 12, 13 lub 14, a po drugie ostatnią cyfrą $liczba_osób musi być 2, 3 lub 4. Nareszcie mamy poprawne wyniki:

12 osób
13 osób
14 osób
122 osoby
54352343 osoby
100004 osoby

Całość skryptu wygląda w ten sposób:

$liczba_osob = 12; // to tylko przykład, możesz zadeklarować dowolną wartość całkowitą
$ostatnia_cyfra = substr($liczba_osob, -1);
if (($liczba_osob != 12 AND $liczba_osob != 13 AND $liczba_osob != 14) AND ($ostatnia_cyfra == 2 OR $ostatnia_cyfra == 3 or $ostatnia_cyfra == 4)):
    echo $liczba_osob." osoby";
else:
    echo $liczba_osob." osób";
endif;

Ten kod oczywiście nie dotyczy tylko i wyłącznie reczoniwka „osoby”, ale praktycznie każdego jednego – można go zastosować do poprawnego odnieniania słowa „komentarze„, co również jest popularnym problemem na polskich stronach WWW. Jestem ciekaw, czy stosujecie inne zabiegi do radzenia sobie w takich przypadkach?