Autor Zpráva
Jack06
Profil
Zdravím, chtěl jsem se zeptat, zda jste někdo neřešil již tento problém:

    public static function aplhabetSort($list) {
        if (!is_array($list))
            return $list;

        setlocale(LC_ALL, "cs_CZ.UTF-8");
        usort($list,'strcoll'); 

        return $list;
    }

Seřadí bez diakritiky abecedně a potom s diakritikou. Já bych potřeboval aby to šlo i jako: c, č, d, ď a to mi bohužel nejde. Prosím tedy o radu. Děkuji
Tori
Profil
Mně tohle funguje. Jsou určitě vstupní data v utf8? Je na serveru nainstalovaná česká lokalizace (pokud není, setlocale vrátí false)?
Jack06
Profil
Mám VertrigoServ a zkouším to na localhostu na windowsech.


// heh to jsem nezkoušel, vrátí mi false, jak ji nainstalovat?
Davex
Profil
Jack06:
zkouším to na localhostu na windowsech
Pro Windows musíš přidat ještě "Czech", ale funguje to trochu divně a nebude to seřazené přesně podle ČSN. Vhodnější nastavení pro UTF-8 se mi najít nepodařilo.

setlocale(LC_ALL, "cs_CZ.UTF-8", "Czech");
Jack06
Profil
Ani tak se mi to neseřadí podle diakritiky. Jak dostat tu českou lokalizaci do serveru? Nebo kde najdu návod jak ji nainstalovat?
Davex
Profil
Jack06:
Jak dostat tu českou lokalizaci do serveru?
Na Windows asi nijak, protože nefunkčnost řazení v UTF-8 je vlastnost PHP pro Win. Řešením by mohlo být řazení textu v kódování windows-1250 nebo změnit operační systém na Linux, kde to funguje.
Jack06
Profil
Davex:
No ono to nakonec asi poběží na linuxu, tak by to mohlo být v pohodě.
Tori
Profil
Jack06:
Ještě by pro windows šla dopsat funkce pro definovatelné řazení znaků (obdoba porovnávání v MySQL), ale když to poběží pod linuxem, tak je to asi jedno.
Jack06
Profil
Tori:
heh asi nevím co tím myslíš. Já doufám, že to dají pod linux :-D
Tori
Profil
Jack06:
Radši nedávám kód, protože to bylo tak narychlo splácané dohromady. Nicméně to fungovalo zhruba takto:

// nadefinuju si porovnávání znaků. Znaky z každé skupiny jsou rovnocenné.
$collationSetup = array('aAáÁ', 'äÄ', 'bB', 'cCçÇ', 'čČ', )'; // atd.
// převedu toto pole do tvaru, kde klíče budou hodnotami, a jednotlivé znaky se změní na klíče:
$collation = array('a'=>0, 'A'=>0, 'á'=>0, 'Á'=>0, 'ä'=>1, 'Ä'=>1, 'b'=>2,); // atd.

// porovnávací funkce pro usort()
function myCmp($string1, $string2) {
  
   // z každého řetězce načtu jeden znak pomocí mb_substr() -> $char1, $char2
    // porovnávám hodnoty $collation[$char1] a $collation[$char2]
        // 1. pokud se liší, vrátím 1 nebo -1
        // 2. pokud jsem na konci některého ze vstupních řetězců, vrátím 1 nebo -1 (podle kratšího z nich)
        // 3. pokud se hodnoty shodují, načtu ze vstupů následující znaky a znovu porovnávám
}
Nějak jsem měla pořešené, abych se zevnitř porovnávací fce dostala k poli $collation bez globálních proměnných - buď statická třída nebo lambda funkce+use($collation), teď už si nevzpomenu jak.
Jack06
Profil
Tori:
jojojo au au, tomu jsem se chtěl vyhnout. TZV vlastnímu parseru na sort :-D. Ale moc díky
Aleš Janda
Profil
Tori:
Tohle může většinou stačit, ale zrovna pro české třífázové řazení by to muselo být o něco složitější ;-)
weroro
Profil
Tori:
Je možné do funkcie usort() vložiť compare funkciu (usort(compare))?
Tori
Profil
weroro:
Druhý parametr usort je callback. Takže ano.

Aleš Janda:
Jasně, neřešila jsem tam ani "ch". Dík za odkaz, zajímavý.
weroro
Profil
Tori:
Druhý parametr usort je callback. Takže ano.
Ja PHP neovládam na nejakej vysokej úrovni ale ak sa to dá použiť, tak som v AS napísal a prepísal do PHP niečo takéto.
$czStrings = "A,Á,B,C,Č,D,Ď,E,É,Ě,F,G,H,CH,I,Í,J,K,L,M,N,Ň,O,Ó,P,Q,R,Ř,S,Š,T,Ť,U,Ú,Ů,V,W,X,Y,Ý,Z,Ž,a,á,b,c,č,d,ď,e,é,ě,f,g,h,ch,i,í,j,k,l,m,n,ň,o,ó,p,q,r,s,t,ť,u,ú,ů,v,w,x,y,ý,z,ž";
$czStringArray = explode(",", $czStrings);

function compare($strA, $strB)
{
    $ret = 0;
    for ($i = 0; $i < strlen($strA); $i++)
    {
        if (getID($strA[$i]) > getID($strB[$i]))
        {
            $ret = 1;
            break;
        }
        else if (getID($strA[$i]) < getID($strB[$i]))
        {
            $ret = -1;
            break;
        }
    }
    return $ret;
}

function getID($char)
{
    $num = count($czStringArray);
    for ($i = 0; $i < count($czStringArray); $i++)
    {
        if ($char == $czStringArray[$i])
        {
            $num = $i;
            break;
        }
    }
    return $num;
}
skutočne sa ospravedlňujem ak je daný kód nelogický. Netestoval som ho a je to voľný prepis z ActionScript do PHP.
Jack06
Profil
velice zajímavé, jen:
1) nebude to moc pomalé??
2) jak do toho comparu chceš vrazit ty 2 chary? usort($list, array($this, 'compare')); ??? toto nebude stačit

Díky za resp
Tori
Profil
weroro:
Řádek 9 bude fungovat jen pro jednobytová kódování, pro utf-8 by muselo být mb_string. Do funkce getID by se v PHP ještě muselo přidat global $czStringArray.

Jack06:
Ještě mi napadlo (ale nezkoušela jsem, možná to je blbost): Zkoušel jste nejdřív texty v poli převést na win-1250 a až pak seřadit?
Jack06
Profil
Tori:
ne nezkoušel :-) a ani mě to nějak nenapadlo :-D
Aleš Janda
Profil
Tori:
Zkoušel jste nejdřív texty v poli převést na win-1250 a až pak seřadit?
Ten převod utf-8 => windows-1250 je ale samozřejmě ztrátový, takže nevím, jestli je to jen kvůli seřazení nejlepší nápad.
Jack06
Profil
Aleš Janda:
iconv je ztrátový?
Aleš Janda
Profil
Jack06:
iconv je ztrátový?
Ano. Nelze do kódování windows-1250, jež pojme max. 256 znaků, narvat celou Unicode tabulku s více než 100.000 znaky, které lze zapsat v utf-8. Windows-1250 pokryje jen znaky střední Evropy, zbytek se prostě zahodí. Viz volby //TRANSLIT a //IGNORE pro řízení toho, co se s takovými znaky má stát.
Čejen
Profil *
Ahoj,
tohle mi funguje i na Windows: usort($array, [new Collator('cs'), 'compare'])
stw
Profil *
Já marně hledal spolehlivě fungující řazení české abecedy, ale když už to umělo diakritiku tak to chybovalo v "Ch".

setlocale(LC_ALL, "cs_CZ.UTF-8", "Czech");
usort($sortarray,'strcoll');
// a nebo
sort($sortarray,SORT_LOCALE_STRING);
fungovalo oboje stejně. Ch bylo mezi C.

Nakonec sem to vyřešil takto, a funguje znamenitě.
    usort($sort_user, "SortCzechChars");

function SortCzechChars($a, $b){
    $a = str_replace('Ch', 'HZZ', $a);
    $a = str_replace('ch', 'hzz', $a);
    $b = str_replace('Ch', 'HZZ', $b);
    $b = str_replace('ch', 'hzz', $b);
    static $czechChars = array('A'=>'A','Á'=>'AZ','B'=>'B','C'=>'C','Č'=>'CZ','D'=>'D','Ď'=>'DZ','E'=>'E','É'=>'EZ','Ě'=>'EZZ','F'=>'F','G'=>'G','H'=>'H','I'=>'I','Í'=>'IZ','J'=>'J','K'=>'K','L'=>'L','M'=>'M','N'=>'N','Ň'=>'NZ','O'=>'O','Ó'=>'OZ','P'=>'P','Q'=>'Q','R'=>'R','Ř'=>'RZ','S'=>'S','Š'=>'SZ','T'=>'T','Ť'=>'TZ','U'=>'U','Ú'=>'UZ','Ů'=>'UZZ','V'=>'V','W'=>'W','X'=>'X','Y'=>'Y','Ý'=>'YZ','Z'=>'Z','Ž'=>'ZZ',
                             'a'=>'a','á'=>'az','b'=>'b','c'=>'c','č'=>'cz','d'=>'d','ď'=>'dz','e'=>'e','é'=>'ez','ě'=>'ezz','f'=>'f','g'=>'g','h'=>'h','i'=>'i','í'=>'iz','j'=>'j','k'=>'k','l'=>'l','m'=>'m','n'=>'n','ň'=>'nz','o'=>'o','ó'=>'oz','p'=>'p','q'=>'q','r'=>'r','ř'=>'rz','s'=>'s','š'=>'sz','t'=>'t','ť'=>'tz','u'=>'u','ú'=>'uz','ů'=>'uzz','v'=>'v','w'=>'w','x'=>'x','y'=>'y','ý'=>'yz','z'=>'z','ž'=>'zz');

    $A = strtr($a, $czechChars);
    $B = strtr($b, $czechChars);

    return strnatcasecmp($A, $B);
}
Keeehi
Profil
stw:
Vyhaž z toho pole identity a bude to ještě lepší.
stw
Profil *
Keeehi:
Ani jsem nečekal že někdo zareaguje ve starém tématu (kde jsem i já hledal řešení). Původně jsem na to šel jinou cestou kde byla potřeba celá abeceda a to byl pozůstatek.

Ještě jsem to překopal:
usort($sortarray, "SortCzechChars");

function SortCzechChars($a, $b){
    static $czechCharsS = array('Á', 'Č', 'Ď', 'É', 'Ě' , 'Ch' , 'Í', 'Ň', 'Ó', 'Ř', 'Š', 'Ť', 'Ú', 'Ů' , 'Ý', 'Ž', 'á', 'č', 'ď', 'é', 'ě' , 'ch' , 'í', 'ň', 'ó', 'ř', 'š', 'ť', 'ú', 'ů' , 'ý', 'ž');
    static $czechCharsR = array('AZ','CZ','DZ','EZ','EZZ','HZZZ','IZ','NZ','OZ','RZ','SZ','TZ','UZ','UZZ','YZ','ZZ','az','cz','dz','ez','ezz','hzzz','iz','nz','oz','rz','sz','tz','uz','uzz','yz','zz');

    $A = str_replace($czechCharsS, $czechCharsR, $a);
    $B = str_replace($czechCharsS, $czechCharsR, $b);

    return strnatcasecmp($A, $B);
}

Vše řadí perfektně včetně . Ale pokud se vyskytne Hžž (takové slovo neznám :-D) tak ho šoupne až za Ch.
Keeehi
Profil
Pořádně to otestuj, ale toto by mělo korektně řadit jakýkoli český řetězec.
function SortCzechChars($a, $b) {
    static $order = array('A' => 1, 'Á' => 2, 'B' => 3, 'C' => 4, 'Č' => 5, 'D' => 6, 'Ď' => 7, 'E' => 8, 'É' => 9, 'Ě' => 10, 'F' => 11, 'G' => 12, 'H' => 13, 'Ch' => 14, 'I' => 15, 'Í' => 16, 'J' => 17, 'K' => 18, 'L' => 19, 'M' => 20, 'N' => 21, 'Ň' => 22, 'O' => 23, 'Ó' => 24, 'P' => 25, 'Q' => 26, 'R' => 27, 'Ř' => 28, 'S' => 29, 'Š' => 30, 'T' => 31, 'Ť' => 32, 'U' => 33, 'Ú' => 34, 'Ů' => 35, 'V' => 36, 'W' => 37, 'X' => 38, 'Y' => 39, 'Ý' => 40, 'Z' => 41, 'Ž' => 42, 'a' => 1, 'á' => 2, 'b' => 3, 'c' => 4, 'č' => 5, 'd' => 6, 'ď' => 7, 'e' => 8, 'é' => 9, 'ě' => 10, 'f' => 11, 'g' => 12, 'h' => 13, 'ch' => 14, 'i' => 15, 'í' => 16, 'j' => 17, 'k' => 18, 'l' => 19, 'm' => 20, 'n' => 21, 'ň' => 22, 'o' => 23, 'ó' => 24, 'p' => 25, 'q' => 26, 'r' => 27, 'ř' => 28, 's' => 29, 'š' => 30, 't' => 31, 'ť' => 32, 'u' => 33, 'ú' => 34, 'ů' => 35, 'v' => 36, 'w' => 37, 'x' => 38, 'y' => 39, 'ý' => 40, 'z' => 41, 'ž' => 42);
    $a = preg_split('//u', $a, -1, PREG_SPLIT_NO_EMPTY);
    $b = preg_split('//u', $b, -1, PREG_SPLIT_NO_EMPTY);
    
    for($i=0; $i<count($a) && $i<count($b); $i++){
        $aChar = $a[$i];
        $bChar = $b[$i];
        if (($aChar === 'c' || $aChar === 'C') && isset($a[$i+1]) && ($a[$i+1] === 'h' || $a[$i+1] === 'H')) {
            $aChar .= 'h';
        }
        if (($bChar === 'c' || $bChar === 'C') && isset($b[$i+1]) && ($b[$i+1] === 'h' || $b[$i+1] === 'H')) {
            $bChar .= 'h';
            $i++;
        }
        
        if ($aChar === $bChar) {
            continue;
        }
        
        $aVal = isset($order[$aChar]) ? $order[$aChar] : 43;
        $bVal = isset($order[$bChar]) ? $order[$bChar] : 43;
    
        if($aVal === $bVal){
            continue;
        }
        
        return $aVal - $bVal;
    }
    return count($a) - count($b);
}
stw
Profil *
Keeehi:
Díky za kód. Určitě si ho uložím, to se může v budoucnu hodit, ale pravděpodobně zůstanu u mého řešení.

V rychlém testu mi to řadilo
Červ A
Čer A
Očekával bych je v opačném pořadí.

V poli mám skutečná "příjmení jméno;číslo;číslo;číslo;číslo;string"
$sortarray[$i] = $user[$i].";".$h[$i].";".$w_h[$i].";".$m[$i].";".$p[$i].";".$string[$i];
Takhle nějak jsem na to šel při prvních testech, s rozdílem prohozených key a value array('A', 'Á', 'B', 'C', 'Č', 'D', 'Ď', 'E', 'É', 'Ě' ...


V dalších testech jsem si všim zajímavého chování. (I když u mně v praxi ta situace nemůže nikdy nastat.)
V poli mám (mimo dalších)
Čer A;1;;;;text
Čer A;2;;;;text
Při každém řazení tyhle dvě prohazuje mezi sebou.
Keeehi
Profil
stw:
Navrhoval jsem to pro řazení slov a ne vět, ovšem změna je velmi jednoduchá, na řádcích 21 a 22 stačí vyměnit číslo 43 za 0 a bude to řadit správně.

Při každém řazení tyhle dvě prohazuje mezi sebou.
To je dané tím, že řetězce jsou považovány za shodné. Jednička a dvojka nejsou definované v poli $order a všem nedefinovaným znakům je přiřazena hodnota 43 (po úpravě za začátku příspěvku to bude 0). Všechny znaky, podle kterých se má řadit musejí být definované v poli $order. Pokud chceš řadit i podle čísel, stačí je tam přidat.

Vaše odpověď


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: