Из mail.google.com можно выгружать контакты как в формате CSV outlook'a, так и и в собственном формате CSV гугла. Первый вариант выгружается нормально, его легко можно распарсить. А вот с собственным CSV-форматом гугла вышла неувязочка. Мне нужно было выдрать определенные поля (их порядковые номера) - я решил распарсить первую строку и по наименованиям получить номера интересующих полей. Т.е. к примеру мне нужно поле Name, я делаю так Код (Text): $data = fgetcsv($handle, 0, $delimiter); for ($i = 0; $i < count ($data); $i++) { if ($data[$i] == 'Name') { // some code ... } } Вроде бы все легко и просто, а ни при каком $i равенство не выходит. Я и так и сяк крутил, а равенства нет. Тогда я прогнал $data[$i] через ord() - оказалось, что все видимые символы разделены символом с нулевым кодом, т.е. примерно так [код символа][0][код символа][0][код символа][0] Подскажите, пожалуйста, как решить данную проблему - избавиться от этого нулевого байта или привести искомую строку (в примере Name) к такому же виду. Есть и еще одна трудность: не везде у меня идет сравнение на строгое равенство, а кое-где используется поиск по регулярке...
Не все так просто оказалось. Это Unicode - для латиницы второй байт пустой, а для кириллицы уже не пустой. Я попробовал перевести обычную строку в юникод - последовательность кодов совпала, но, если я делаю вот так Код (Text): $line = 'Кириллица'; echo 'line = ' . $line . '('; for($z=0;$z<strlen($line);$z++) echo '[' . ord($line[$z]) . '] '; echo ')'; то получаю такой результат line = ��8@8;;8F0([255], [254], [26], [4], [56], [4], [64], [4], [56], [4], [59], [4], [59], [4], [56], [4], [70], [4], [48], [4], ) строку предваряют символ из двух байтов 255 и 254, который не является пробельным - trim его не удаляет
если бы все так было просто, я бы не задавал вопрос)))))) При попытке перекодировать гугловские данные получается вообще фигня... А, перекодируя искомые данные, я сталкиваюсь с тем, что: 1) в начало втыкается непонятный символ [255][254] 2) пока не удалось грамотно перекодировать регулярное выражение, чтобы оно оставалось рабочим - постоянно вылезало сообщение no ending delimiter found, хотя вроде все спецсимволы я и пытался перекодировать и оставлял их в неизменном виде и вообще, как оказалось, нет ничего общего у выгрузки из гугла контактов методом Outlook с реальной выгрузкой контактов из Outlook'a. Контакты из outlook'a выгрузились в cp1251 и никаких проблем не вызвали при обработке. Тут возник еще прелюбопытный вопрос - якобы в php крайне не рекомендуется извлекать из строкового значения отдельные символы как элементы массива, т.е. не рекомендуется делать вот так: Код (Text): $string = 'some string'; $index = 0; //some number value echo $string[$index]; Для этих целей рекомендуется либо использовать substr со смещением, либо обращаться не через квадратные, а через фигурные скобки: Код (Text): $string = 'some string'; $index = 0; //some number value echo $string{$index}; Почему так?
Если использовать кодировку utf-8 и в строке текста будут русские символы - то такой подход Код (PHP): $string{$index} просто не будет работать как надо. Русские символы в кодировке utf-8 занимают два байта. А вышеприведённое выражение в PHP - выбирает байты из строки. Не символы, а именно байты. То есть будет получено "пол-символа".
Мне на то, что не рекомендуется обращаться к строке, как к массиву, давали следующие аргументы: 1) При попытке обратиться по индексу к несуществующему элементу (т.е. строка к примеру состоит из десяти символов, а обращаемся к двадцатому) вылетает ошибка 2) Вопрос о том, насколько больше нагружает обращение по индексу по сравнению с поиском через {} или функцией substr провел маленький эксперимент: 3) В книжке написано, что рекомендуется использовать имена переменных длиной до 7 символов, т.к. они существенно быстрее обрабатываются Код (Text): $str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; echo '<span style="color: red">str[320] = ' . ($str[320]) . '</span><br /><br />'; echo '<span style="color: red">str{320} = ' . ($str{320}) . '</span><br /><br />'; $i = 0; $start = microtime(true); while ($i < 1000000) { $s = substr($str, 150, 1); $i++; } echo 'substr (str) = ' . (microtime(true) - $start) . '<br /><br />'; $i = 0; $start = microtime(true); while ($i < 1000000) { $s = $str[150]; $i++; } echo '[] (str) = ' . (microtime(true) - $start) . '<br /><br />'; $i = 0; $start = microtime(true); while ($i < 1000000) { $s = $str{150}; $i++; } echo '{} (str) = ' . (microtime(true) - $start) . '<br /><br />'; $string7 = $str; $i = 0; $start = microtime(true); while ($i < 1000000) { $s = substr($string7, 150, 1); $i++; } echo 'substr ($string7) = ' . (microtime(true) - $start) . '<br /><br />'; $i = 0; $start = microtime(true); while ($i < 1000000) { $s = $string7[150]; $i++; } echo '[] ($string7) = ' . (microtime(true) - $start) . '<br /><br />'; $i = 0; $start = microtime(true); while ($i < 1000000) { $s = $string7{150}; $i++; } echo '{} ($string7) = ' . (microtime(true) - $start) . '<br /><br />'; $werylengthstringname = $str; $i = 0; $start = microtime(true); while ($i < 1000000) { $s = substr($werylengthstringname, 150, 1); $i++; } echo 'substr ($werylengthstringname) = ' . (microtime(true) - $start) . '<br /><br />'; $i = 0; $start = microtime(true); while ($i < 1000000) { $s = $werylengthstringname[150]; $i++; } echo '[] ($werylengthstringname) = ' . (microtime(true) - $start) . '<br /><br />'; $i = 0; $start = microtime(true); while ($i < 1000000) { $s = $werylengthstringname{150}; $i++; } echo '{} ($werylengthstringname) = ' . (microtime(true) - $start) . '<br /><br />'; Результаты (пока эксперимент проводился под windows 7 максималка): str[320] = str{320} = substr (str) = 0.5581591129303 [] (str) = 0.28874492645264 {} (str) = 0.2863290309906 substr ($string7) = 0.55512809753418 [] ($string7) = 0.29122090339661 {} ($string7) = 0.28695893287659 substr ($werylengthstringname) = 0.55270504951477 [] ($werylengthstringname) = 0.28703498840332 {} ($werylengthstringname) = 0.28970217704773 В первой строке сразу видно, что никакой ошибки при обращении к несуществующему индексу не вылетает ни при [], ни при {}. Далее идут три блока: блок, в котором имя переменной состоит из трех символов, блок с переменной из 7 символов и блок с переменной из 20 символов. Как видно, разницы никакой нет. Также нет разницы по времени между обращением через [] и через []. Зато substr отрабатывает вдвое медленнее. Так что пока так и осталось непонятным, почему не рекомендуется обращаться со строкой, как с массивом при извлечении символов...
Для того, чтобы увидеть сообщение об ошибке - нужно, чтобы было включено их отображение и чтобы выводились все ошибки, в том числе и нотисы: Код (PHP): <?php ini_set('display_errors', true); error_reporting(E_ALL); $str = 'abcdefg'; echo($str{9}); ?> Этот код приведёт к ошибке А ты читал моё предыдущее сообщение? На счёт скорости выполнения - да, обращение по индексу работает быстрее. Но при использовании кодировки utf-8 (и вообще любой не однобайтовой кодировки) - на практике не применимо.
Про репортирование обо всех ошибках забыл... Остается открытым вопрос, насколько это критично и правильно: либо жертвовать скоростью (вряд ли когда-нибудь придется перебирать мегабайты текста посимвольно), либо забить на эти нотисы и писать более читабельно и кратко?
Я бы использовал $str{$index} - если программа не предполагает работу с текстом в кодировке utf-8 (то есть если использется однобайтная кодировка, типа Windows-1251). Если используется кодировка utf-8 - только функции mb_string. Добавлено спустя 2 минуты 17 секунд: И да, при использовании $str{$index} - я бы нотисов избегал, заранее определяя длину строки, а не обращаясь "вслепую" к какому-то символу в строке. Впрочем, при использовании функций - я тоже сперва определю длину строки.