Специальные символы, отбрасывающие str_pad в php?

Я пишу модуль, который должен иметь возможность экспортировать записи транзакций в формате BankOne.

Вот спецификация формата

Вот пример файла

Поля помещаются в определенные диапазоны на линии, а записи разделяются новыми строками. Необходимо добавить много пространств для обеспечения того, чтобы поля начинались и заканчивались в определенных точках линии.

Для этого я написал функцию php. Он берет в полях как параметры и должен возвращать правильно отформатированную запись.

function record4($checknum='', $nameid='', $purpose='', $pledge='', $payment='', $frequency='', $title='', $fname='', $lname='', $suffix='', $address='', $postalcode='', $city='', $state='', $greeting='') { $fields = array( 'checknum' => array('length' => 8, 'start' => 37), 'nameid' => array('length' => 7, 'start' => 45), 'purpose' => array('length' => 5, 'start' => 52), 'pledge' => array('length' => 10, 'start' => 57), 'payment' => array('length' => 10, 'start' => 67), 'frequency' => array('length' => 1, 'start' => 77), 'title' => array('length' => 20, 'start' => 78), 'fname' => array('length' => 40, 'start' => 98), 'lname' => array('length' => 40, 'start' => 138), 'suffix' => array('length' => 20, 'start' => 178), 'address' => array('length' => 35, 'start' => 198), 'postalcode' => array('length' => 10, 'start' => 233), 'city' => array('length' => 28, 'start' => 243), 'state' => array('length' => 5, 'start' => 271), 'greeting' => array('length' => 40, 'start' => 276) ); $str = '4'; foreach($fields as $field_name => $field) { if($$field_name) { $str = str_pad($str, $field['start']-1, ' '); $str = $str.substr(trim((string)$$field_name), 0, $field['length']); } } return $str."\n"; } 

Кажется, он работает по назначению, но когда я посмотрел на выходной файл, я нашел это (прокрутите до конца):

 4 1 David Landrum 4 3 Hazel Baker 4 3 Jerome Zehnder 4 1 VÃctor Nadales 4 2 Philip Nauert 4 1 Jana Ortcutter 

Файл содержит 900 записей, извлеченных из базы данных, все они отформатированы правильно, за исключением VÃctor Nadales. После этого первого имени каждое другое поле имеет три пространства слева от того места, где оно должно быть. Единственная аномальная вещь об этой записи, по-видимому, является «Ã» от первого имени.

Предполагается, что функция должна выровнять строку до необходимой длины после каждого обрабатываемого поля, но она каким-то образом обманывается в этой строке?

Может ли кто-нибудь сказать мне, что здесь происходит?

EDIT: Я просто понял, что все импортирующие файлы этого формата могут даже не поддерживать специальные символы UTF-8. Поэтому я добавил эту строку в свой код:

 $$field_name = iconv('UTF-8', 'ASCII//TRANSLIT', $$field_name); 

Г-м выглядит следующим образом: ~ A-. Не идеально, но, по крайней мере, файл теперь отформатирован правильно.

Solutions Collecting From Web of "Специальные символы, отбрасывающие str_pad в php?"

Это происходит потому, что 'Ã' является многобайтовым символом (длиной 4 байта), а str_pad подсчитывает байты, а не логические символы.

Вот почему вам не хватает трех пробелов, str_pad подсчитывает 'Ã' как 4 одиночных байтовых символа вместо одного многобайтового.

Попробуйте эту функцию ( кредит здесь ).

 <? function mb_str_pad( $input, $pad_length, $pad_string = ' ', $pad_type = STR_PAD_RIGHT) { $diff = strlen( $input ) - mb_strlen( $input ); return str_pad( $input, $pad_length + $diff, $pad_string, $pad_type ); } ?> 

Используя решение Gordon, вам просто нужно добавить тип кодировки в mb_strlen и он будет правильно считать байты (по крайней мере, это сработало для меня)

Вот функция, которую я использовал:

 function mb_str_pad( $input, $pad_length, $pad_string = ' ', $pad_type = STR_PAD_RIGHT, $encoding="UTF-8") { $diff = strlen( $input ) - mb_strlen($input, $encoding); return str_pad( $input, $pad_length + $diff, $pad_string, $pad_type ); } 

Кредит за идею здесь

 function mb_str_pad($input, $pad_length, $pad_string = ' ', $pad_type = STR_PAD_RIGHT) { $diff = strlen($input) - mb_strlen($input,mb_detect_encoding($input)); return str_pad($input, $pad_length + $diff, $pad_string, $pad_type); }