2012-08-08 34 views
7

Estoy escribiendo un módulo que se supone que puede exportar registros de transacciones en formato BankOne.Caracteres especiales arrojando str_pad en php?

Here is the specification of the format

Here is an example file

Los campos se ponen en intervalos específicos en la línea y los registros están separados por nuevas líneas. Se deben agregar muchos espacios para garantizar que los campos comiencen y terminen en puntos específicos de la línea.

Escribí una función en php para esto. Toma los campos como parámetros y debe devolver un registro con el formato correcto.

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"; 
} 

Parece que funciona según lo previsto, pero cuando miré en el archivo de salida que encontré este (desplazarse hasta el final):

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 

El archivo contiene 900 registros extraídos de una base de datos, todos de ellos están formateados correctamente, excepto Víctor Nadales. Después de ese primer nombre, cada otro campo queda a tres espacios de donde se supone que debe estar. Lo único anómalo sobre este registro parece ser el 'Ã' en el primer nombre.

Se supone que la función rellena la cadena a la longitud adecuada después de cada campo que procesa, pero de alguna manera se deja engañar en esta línea.

¿Alguien puede decirme qué está pasando aquí?

EDITAR: Me acabo de dar cuenta de que los archivos importados de este formato podrían incluso no admitir caracteres especiales UTF-8. Por lo tanto, agregué esta línea a mi código:

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

El à sale luciendo así: ~ A-. No es ideal, pero al menos el archivo está formateado correctamente ahora.

+0

es más probable una problema de cadena multibyte (vea las funciones 'mb_str *'). – Crontab

+0

Supongo que es porque ''Ã'' tiene cuatro bytes de longitud, y' str_pad' cuenta bytes en lugar de caracteres lógicos. –

Respuesta

10

Esto está sucediendo porque 'Ã' es un carácter de varios bytes (4 bytes de longitud) y str_pad cuenta bytes en lugar de caracteres lógicos.

Esta es la razón por la que te faltan tres espacios, str_pad está contando 'Ã' como 4 caracteres de un solo byte en lugar de uno de varios bytes.

Pruebe esta función (credit here).

<? 
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); 
} 
?> 
+0

Gracias por su respuesta.Probé la función que me diste, sin embargo, parece que sigue tropezando en la misma línea. Cambié substr a mb_substr también. – Peronix

+0

Hmm, impar No he probado personalmente la función, pero pensé que funcionaría. ¿Cuál es la salida de 'mb_strlen' contra' strlen' en su cadena de entrada Unicode? ¿Está detectando correctamente el carácter de múltiples bytes? –

+0

mb_strlen ("Víctor") y strlen ("Víctor") ambos devuelven int (9) =/ – Peronix

6

Utilizando la solución de Gordon sólo hay que añadir el tipo de codificación a la mb_strlen y empezará a contar los bytes correctamente (al menos a mí me funcionó)

Aquí está la función utilicé:

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); 
} 

de crédito a la idea here

2
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); 
} 
+1

¿Podría explicar su respuesta? – i3arnon

+0

autodetecta la codificación de cadena de entrada en el segundo parámetro de mb_strlen utilizando mb_detect_encoding, por lo que no es necesario agregar otro parámetro a la llamada de función en sí –