Сохраняйте целочисленные и плавающие типы при преобразовании данных CSV в массивы PHP с помощью str_getcsv и fgetcsv

При использовании PHPs str_getcsv-функции числа будут обрабатываться как строки:

<?php
$csv = str_getcsv('0,1.2,"string"');
var_dump( $csv );
/* result: array(3) {
  [0]=>string(1) "0"
  [1]=>string(3) "1.2"
  [2]=>string(6) "string"
} */
/* DESIRED result: array(3) {
  [0]=>int(0)
  [1]=>float(1.2)
  [2]=>string(6) "string"
} */

То же самое верно и для fgetcsv-функции. Как преодолеть эту проблему, не перебирая впоследствии массив и, так сказать, вручную конвертируя каждое значение.

Просто чтобы было ясно - я не ищу обходной путь, например:

<?php
$csv = str_getcsv('0,1.2,"string"');
foreach ( $csv as &$v ) if ( is_numeric( $v ) ) $v += 0;
var_dump( $csv ); // desired result

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

Как преодолеть эту проблему, не перебирая впоследствии массив и не преобразовывая обратно каждое значение вручную. Вы не можете, CSV-файл является текстовым и обрабатывается как таковой.

AbraCadaver 11.12.2020 17:48

Мне очень нравится этот обходной путь.

Nigel Ren 11.12.2020 17:53

@AbraCadaver уверен, что ты прав. csv является текстовым, но также может представлять числовые значения. Что не означает, что вы ошибаетесь, когда говорите: "Вы не можете"...

Axel 11.12.2020 17:54

Я имел в виду, что вам придется что-то делать с данными после их получения из csv. Обходной путь @NigelRen выглядит лучшим. Просто напишите свою собственную функцию, которая включает в себя get csv и json_decode.

AbraCadaver 11.12.2020 17:57

Ты сдался?

AbraCadaver 10.01.2021 05:15

Вовсе нет @AbraCadaver. Я получил свое решение, а также более глубокое понимание. Тоже оставил ответ...

Axel 10.01.2021 13:03
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
1
6
1 080
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Мы можем закрыть это как дубликат, но мне скучно. json_decode будет декодироваться в int, float и boolean и быстрее, чем другие подходы:

function str_getcsv_typed($string, $delimiter = ",", enclosure='"', $escape = "\\") {
    return json_decode('[' . str_getcsv($string, $delimiter, enclosure, $escape) . ']');
}

function file_getcsv_typed($handle, $length=0, $delimiter = ",", enclosure='"', $escape = "\\") {
    return json_decode('[' . fgetcsv($handle, $length, $delimiter, enclosure, $escape) . ']');
}

Если в вашем CSV-файле есть что-то, что находится в формате объекта или массива JSON, он также может декодировать их, возможно, не то, что вам нужно. Кроме того, если есть какие-либо недопустимые символы или синтаксис JSON, это также не удастся.

Можно ссылку на дуп? Есть много вопросов, касающихся разбора CSV-файлов и строк, но на самом деле ни один из них не относится к проблеме типа. stackoverflow.com/questions/9593765/… не особо про csv. Спасибо и +1 в любом случае... Не нравится, что вам скучно...

Axel 11.12.2020 18:33

Это тот, если кто-то не найдет лучше.

AbraCadaver 11.12.2020 18:39
Ответ принят как подходящий

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

<?php
$csv = '0,1.2,"string"';
json_decode( "[$csv]", true );

Но имейте в виду, что это не удастся, по крайней мере, с многострочными значениями!

Вот несколько тестов:

<?php
$csv = '0,1.2,"string"';
var_dump(
  json_decode( "[$csv]", true ) // works
  , str_getcsv( $csv )          // converts everything to string
);
/*
array(3) { json_decode
  [0]=>int(0)
  [1]=>float(1.2)
  [2]=>string(6) "string"
}
array(3) { str_getcsv
  [0]=>
  string(1) "0"
  [1]=>
  string(3) "1.2"
  [2]=>
  string(6) "string"
}
*/
$csv = '", as value in ,-separated csv"';
var_dump(
  json_decode( "[$csv]", true ) // works also when separator is part of value
  , str_getcsv( $csv )          // works also when separator is part of value but converts everything to string
);
/*
array(1) { json_decode
  [0]=>string(29) ", as value in ,-separated csv"
}
array(1) { str_getcsv
  [0]=>string(29) ", as value in ,-separated csv"
}
*/
$csv = '0,"value
with multiline"';
var_dump(
  json_decode( "[$csv]", true ) // doesn't work as JSON can't handle multilines
  , str_getcsv( $csv )          // works also with multilines but converts everything to string
);
/*
NULL json_decode
array(2) { str_getcsv
  [0]=>string(1) "0"
  [1]=>string(21) "value
              with multiline"
}
*/

Очень надежным способом кажется версия из моего исходного вопроса, поскольку она опирается на нативную str_getcsv-функцию и впоследствии преобразуется в соответствующие типы. С точки зрения производительности это не кажется мне идеальным, но это должно беспокоить только при работе с очень тяжелыми струнами (что касается меня).

<?php
$csv = str_getcsv('0,1.2,"string"');
foreach ( $csv as &$v ) if ( is_numeric( $v ) ) $v += 0;

Другие вопросы по теме