Замена или удаление новой строки чем-то другим, но только между одинарными или двойными кавычками с использованием PHP в файле CSV - PullRequest
1 голос
/ 09 октября 2008

У меня есть CSV-файл, содержащий около 200 000–300 000 записей. Большинство записей можно разделить и вставить в базу данных MySQL с помощью простого

$line = explode("\n", $fileData);

, а затем значения, разделенные

$lineValues = explode(',', $line);

и затем вставляется в базу данных, используя правильный тип данных, то есть int, float, string, text и т. Д.

Однако у некоторых записей есть текстовый столбец, который включает в себя \ n в строке. Который ломается при использовании $ line = explode ("\ n", $ fileData); метод. Каждая строка данных, которая должна быть вставлена ​​в базу данных, имеет приблизительно 216 столбцов. не каждая строка имеет запись с \ n в строке. Однако каждый раз, когда в строке находится \ n, он заключается в пару одинарных кавычек (')

каждая строка настроена в следующем формате:

id,data,data,data,text,more data

пример:

1,0,0,0,'Hello World,0
2,0,0,0,'Hello
    World',0
3,0,0,0,'Hi',0
4,0,0,0,,0

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

Новые строки только \ n, и файл вообще не включает \ r в файл.

Ответы [ 5 ]

3 голосов
/ 09 октября 2008

Другой совет здесь, конечно, действителен, особенно если вы хотите написать свой собственный анализатор CSV, однако, если вы просто хотите получить данные, используйте функцию fgetcsv () и don не беспокойтесь о деталях реализации.

1 голос
/ 09 октября 2008

Если данные csv находятся в файле, вы можете просто использовать fgetcsv (), как указали другие. fgetcsv правильно обрабатывает встроенные символы новой строки.

Однако, если ваши данные CSV находятся в строке (например, $ fileData в вашем примере), следующий метод может быть полезен, поскольку str_getcsv () работает только со строкой за раз и не может разбить весь файл на записи.

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

Как только у вас будет полная запись, разбейте ее на кавычки (снова используя explode ()). Нечетные поля заключаются в кавычки (таким образом, встроенные запятые не являются специальными), четные поля не являются.

Пример:

# Split file into physical lines (records may span lines)
$lines = explode("\n", $fileData);

# Re-assemble records
$records = array ();
$record = '';
$lineSep = '';
foreach ($lines as $line) {
  # Escape @ symbol so we can use it as a marker (as it does not conflict with
  # any special CSV character.)
  $line = str_replace('@', '@a', $line);

  # Escape commas as we don't yet know which ones are separators
  $line = str_replace(',', '@c', $line);

  # Escape quotes in a form that uses no special characters
  $line = str_replace("\\'", '@q', $line);
  $line = str_replace('\\', '@b', $line);

  $record .= $lineSep . $line;
  $lineSep = "\n";

  # Must have an even number of quotes in a complete record!
  if (substr_count($record, "'") % 2 == 0) {
    $records[] = $record;
    $record = '';
    $lineSep = '';
  }
}
if (strlen($record) > 0) {
  $records[] = $record;
}

$rows = array ();

foreach ($records as $record) {
  $chunks_in = explode("'", $record);
  $chunks_out = array ();

  # Decode escaped quotes/backslashes.
  # Decode field-separating commas (unless quoted)
  foreach ($chunks_in as $i => $chunk) {
    # Unescape quotes & backslashes
    $chunk = str_replace('@q', "'", $chunk);
    $chunk = str_replace('@b', '\\', $chunk);
    if ($i % 2 == 0) {
      # Unescape commas
      $chunk = str_replace('@c', ',', $chunk);
    }
    $chunks_out[] = $chunk;
  }

  # Join back together, discarding unescaped quotes
  $record = join('', $chunks_out);

  $chunks_in = explode(',', $record);
  $row = array ();
  foreach ($chunks_in as $chunk) {
    $chunk = str_replace('@c', ',', $chunk);
    $chunk = str_replace('@a', '@', $chunk);
    $row[] = $chunk;
  }
  $rows[] = $row;
}
1 голос
/ 09 октября 2008

как насчет ручной итерации по данным, от начала до конца, с циклом for или двумя? Это медленнее, чем explode(), но легче получить последовательные и надежные результаты в отношении кавычек.

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

0 голосов
/ 09 октября 2008

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

0 голосов
/ 09 октября 2008

Если вы можете быть уверены, что каждая новая строка, начинающаяся с номера, является действительной новой строкой (т.е. не в середине текстового описания), тогда вы можете попробовать что-то вроде следующего:

// Replace all new-line then id patterns with new-line 0+id
$line = preg_replace('/\n(\d)/',"\n0$1",$line);

// Split on new-line then id
$linevalues = preg_split("/\n\d/",$data);

Первый шаг идентифицирует все строки, которые имеют новую строку, за которой следует числовое значение. Затем он добавляет «0» к этому числовому значению. Вторая строка разбивается там, где находится новая строка, а затем целое число.

"0" добавляется в начало идентификатора, так как preg_split удаляет символы, которые ему соответствуют, из последующих совпадений.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...