Autor Zpráva
4ever
Profil
Ahoj, mám prosbu, jestli by mi někdo poradil.

Mám takovou metodu na načítání dat ze souboru po jednom řádku. V tomto pokusu jde o to najít konce řádků.

  public function readline($fd){
      static $chars; // počítá/pamatuje kolik znaků je celkem 
      $line = fgets($fd);
      $count = strlen($line); /** KOLIK ZNAKŮ JSEM JIŽ ČETL - 
                                  NIKOLIV KOLIK ZNAKJŮ JE V ZÁSOBNÍKU!
                                  **/
      $chars += $count; // přičíst počet znaků
      $this->lines[] = array($count,$chars); // chars till now ... uložit počet znaků od začátku zásobníku
    return $line;
  }


Soubor pak čtu pomocí:
while (!feof ($fd)): 
  $line = $this->buffer->readline($fd);
  $buffer .= $line;
endwhile;

Stručně.

Ta metoda má počítat pro každý řádek:
index 0 - jakou má řádek délku
index 1 - kolik dat bylo načteno celkem

Snažím se pak ořezat ze zásobníku určitý počet řádků a informaci získávám z instance, z pole $buffer->lines . Jenže nějak mi to nepasuje.

Když spustím toto:
foreach ($this->buffer->lines as $arr)
    echo ord($buffer[$arr[1]-1])." is pos $arr[1] is char ".$buffer[$arr[1]-1]."<br>";
die();


Tak získám výstup:
10 is pos 123 is char
10 is pos 198 is char
10 is pos 200 is char
10 is pos 202 is char
108 is pos 245 is char l
48 is pos 321 is char 0
115 is pos 372 is char s
99 is pos 434 is char c
46 is pos 509 is char .
121 is pos 574 is char y
155 is pos 620 is char ›
97 is pos 663 is char a
111 is pos 754 is char o
99 is pos 859 is char c
97 is pos 947 is char a

Povedlo se najít/ověřit pouze 4 řádky, zbytek nepasuje. Čím to může být?
meris
Profil
mohla by být chyba v kodování, některé znaky UTF jsou více bytové, a např dvou bytový znak se počítá jako dva znaky.
4ever
Profil
A jak to vyřešit opravit? Kde vzniká chyba - v tom strlen() nebo v tom vrácení znaku?
4ever
Profil
Jak zadat pro příkaz
$encoding_check = mb_check_encoding($line,
"Windows-1250");
Platné kodování Windows-1250, aby to nevracelo chybu?

Warning: mb_check_encoding() [function.mb-check-encoding]: Invalid encoding "Windows-1250" in ...

Ověřil bych jestli tam není nějaký jiný znak než pro Windows-1250
meris
Profil
podporovaná kódování
Majkl578
Profil
4ever:
Mám takovou metodu na načítání dat ze souboru po jednom řádku.
Na to už funkci máme, říká se jí file.

4ever:
Nemůžeš pomocí mbstring (multibytové rozšíření) kontrolovat jednobajtové řetězce.
Použij iconv a konvertuj si načtený řetězec do UTF-8 a pak s ním adekvátně zacházej (mb_strlen apod.).
4ever
Profil
Majkl578:
File načítá celý soubor. Mě jde o to načíst určité množství řádků. To na čem teď dělám potřebuje načíst řádky v rozsahu 67 až 97. (Celkem je v souboru 127 řádků).

Funkci iconv už využívám.

Můj skript je ve formátu UTF-8. Protože ale zdrojový soubor obsahuje Windows-1250, převádím data nejdříve do UTF-8, potom porovnávám to co bylo zadáno v konfiguračním souboru (UTF-8) s těmi daty a vracím výsledek. Tento výsledek následně opět překonvertuji do Windows-1250 aby se to zobrazilo v originálním kodování. Druhá možnost bude zapsat výsledek do databáze (Windows-1250). Takže to podstatné se odehrává v UTF-8.
4ever
Profil
Wow. Tak už (nebo teprve teď) jsem na to snad přišel. Do metody readline() jsem přidal:
echo ord($line[$count-2])."<br>";

a dostal jsem všude hodnotu 10 (poslední dva znaky jsou 13, 10 konec řádku).

Pak jsem se díval jak volám tu metodu:

$line = $this->buffer->readline($fd);
$line = $this->encode($line); // převádí na UTF-8
$contents .= $line; // (contents je buffer omezený horním limitem)


Po odstranění encode() a testovacího řádku výše dostávám opět správné hodnoty 10.

Dále jsem dělal nějaké opravy, ale výsledek je stále s chybama.

Syntaxe příkazu který tam zadávám při tom konvertování je:
iconv("CP1252", "UTF-8", "nejaky text ve Windows-1250")


Tak ještě uvádím jak získávám kódování ve třídě Read_class:

class Read_class {
    private $c;    
    private $main;
    private $buffer;
    private $colors;
    private $source_encoding; // @string - získáné platné kódování
    
    public function __construct(&$main) {
      $this->main = $main;
      $this->c = $main->c;
      $this->source_encoding = $main->c->encoding->source;
      if (strtolower($this->source_encoding)=="windows-1250") $this->source_encoding = "CP1252";
    } 

public function encode($source){
  if ($this->c->encoding->convert):  
    if ($this->source_encoding){
      if ($this->c->encoding->auto) $this->main->errors->init_errors[333] = "config->encoding->auto is activated. config->encoding->source ".$this->c->encoding->source." is deprived.";
      else $target = iconv($this->source_encoding, $this->c->encoding->target, $source);
    }
    elseif (!$this->c->encoding->auto) $this->main->errors->init_errors[334] = "config->encoding->source not set.";
    else $this->main->errors->init_errors[335] = "config->encoding->auto feature not implemented yet.";
    return $target;  
  else: 
    return $source;
  endif;
}


A ta metoda na převod tam je taky. Chyba musí být někde tady.
Majkl578
Profil
4ever:
a dostal jsem všude hodnotu 10 (poslední dva znaky jsou 13, 10 konec řádku).
To je CRLF, konec řádku na Windows. Linux má jen LF (0xA resp. 10 decimálně) a Macintosh má jen CR (0xD resp. 13).
Zkus při otvírání souboru použít u módu navíc ještě t popř. i b. O koncích řádků se píše v dokumentaci pod seznamem módů.
Zkus trochu rozepsat co je tvým cílem, ať se můžeme zamyslet nad konkrétním (třeba i alternativním) řešením a nevěštíme z nefunčního kódu co má dělat.

Jen mimo téma, ta třída moc rozumně nevypadá, navíc, aby se v tom (s prominutím) prase vyznalo.
4ever
Profil
Majkl578:
Ta třída je zkrácená a to echo tam bylo jen pro test, to tam vůbec nemá být, sorry.

$this->c nebo $main->c je objekt s konfigurací. Jasně, to máš pravdu, že tohle nejde z kódu vyčíst. Měl bych psát třeba config, ale toto je kratší

Nevím jestli si mi porozuměl. Ten soubor se povedlo načíst bezchyby. Problém je ve funkce na převod do kódování UTF-8.
Majkl578
Profil
4ever:
Problém je ve funkce na převod do kódování UTF-8.
Aha, já podle [#8] myslel, že s kódováním. Jaká přesně je to chyba? Nejde o „Detected an illegal character in input string“?
4ever
Profil
Viz #8:
Když druhý řádek zakomentuju
$line = $this->buffer->readline($fd);
// $line = $this->encode($line); // převádí na UTF-8
$contents .= $line; // (contents je buffer omezený horním limitem)


Tak to bude vypisovat konce řádků správně. Tzn. že v metodě encode je chyba. A ta chyba je v tom iconv() (edit: škrtám tuto větu).

Zadávám tam přesně toto
iconv("CP1252", "UTF-8", ... a tady jsou vstupní data ... ).



Tedy metoda realine() načte řádek a výstup se uloží do proměnné $line.
Proměnnou $line ve formátu windows-1250 pak chci zkonvertovat do UTF-8. Výsledek funkce encode je text v UTF-8, který má jinou délku než původní text. Teď mě napadlo, že bych tu konverzi měl provést úplně někde jinde.

Dobrá, tak já to celé vysvětlím ještě takto:
1. Načítám řádek metodou realine().
2. Uvnitř metody realine() spočítám délku řetězce (Windows-1250) a uložím to. a zde je ta chyba
3. pak řetězec vrátím do rodičovské metody
4. v rodičovské metodě to převedu na UTF-8.
5. budu provádět hledání v retězci (zásobníku) pomocí preg_match

Čili řešení je jasné. Přehodit 4 a 2. Nejdříve to zkonvertovat do UTF-8, pak spočítat délku, uložit délku, a pak pokračovat. Provést omezení zásobníku na minimum, provést preg_match a vrátit výsledek.

Řetězec v UTF-8 má jinou délku než Windows-1250.

Asi tak
Majkl578
Profil
Samozřejmě, že má jinou délku, protože strlen počítá bajty a např. diakritika má v UTF-8 dva bajty. Musíš použít mb_* funkce - mb_strlen, mb_substr apod. Problém je tedy pravděpodobně ve 2. kroku s funkcí strlen.
Mimochodem, k UTF-8 řetězci pak nemůžeš přistupovat pomocí indexů ($string[$offset]), protože jde zas o bajtový offset, viz výše. Musíš použít mb_substr.
4ever
Profil
Majkl578:
OK dík
4ever
Profil
Problém s kódováním jsem už vyřešil

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

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

0