2009-10-08 5 views
1

Je suis en train de charger le fichier ascii suivant dans Matlab en utilisant la charge()Problème (bug?) Données hexadécimaux de chargement dans Matlab

% some comment 
1 0xc661 
2 0xd661 
3 0xe661 

(Ceci est en fait un fichier simplifié. Le fichier réel que je suis en essayant de charge contient un nombre indéfini de colonnes et un nombre indéfini de lignes de commentaires au début, ce qui est la raison pour laquelle la fonction de charge était attrayante)

pour une raison étrange, j'obtenir ce qui suit:

K>> data = load('testMixed.txt') 

data = 

     1  50785 
     2  58977 
     3  58977 

J'ai observé que le problème se produit chaque fois qu'il y a un "d" dans le nombre hexadécimal.

conversion directe HEX2DEC fonctionne correctement:

K>> hex2dec('d661') 
ans = 
     54881 

importdata semble avoir le même problème de conversion, et le fait le ImportWizard:

K>> importdata('testMixed.txt') 

ans = 

     1  50785 
     2  58977 
     3  58977 

Est-ce un bug, j'utilise la fonction de charge d'une manière interdite, ou y a-t-il quelque chose d'évident que je néglige?

Y a-t-il des solutions de contournement autour du problème, en sauvant de réimplémenter l'analyse de fichier sur mon propre?

J'ai modifié mon fichier d'entrée pour mieux refléter mon format de fichier réel. J'avais un peu trop simplifié dans ma question initiale.

+0

Est-ce que toutes vos colonnes vont avoir différents types de données (comme des entiers, des valeurs hexadécimales, des flottants, etc.)? – gnovice

+0

J'ai des nombres entiers et hexadécimaux, mélangés – Kena

+0

Je suis un peu surpris que vous ayez CHARGÉ de vous donner * n'importe quels nombres du tout pour les valeurs hexadécimales, sans parler des erreurs. Quand je l'essaie (en utilisant MATLAB 7.8.0 (R2009a)), il renvoie juste les zéros en tête et rien d'autre. – gnovice

Répondre

3

"GOLF" RÉPONSE:

Cela commence par la réponse de mtrw et raccourcit encore:

fid = fopen('testMixed.txt','rt'); 
data = textscan(fid,'%s','Delimiter','\n','MultipleDelimsAsOne','1',... 
       'CommentStyle','%'); 
fclose(fid); 
data = strcat(data{1},{' '}); 
data = sscanf([data{:}],'%i',[sum(isspace(data{1})) inf]).'; 

réponse précédente:

Ma première pensée était d'utiliser TEXTSCAN , car il a une option qui vous permet d'ignorer certaines lignes comme des commentaires quand ils commencent avec un caractère donné (comme %). Cependant, TEXTSCAN ne semble pas gérer correctement les nombres au format hexadécimal. Voici une autre option:

fid = fopen('testMixed.txt','r');  % Open file 

% First, read all the comment lines (lines that start with '%'): 

comments = {}; 
position = 0; 
nextLine = fgetl(fid);    % Read the first line 
while strcmp(nextLine(1),'%') 
    comments = [comments; {nextLine}]; % Collect the comments 
    position = ftell(fid);    % Get the file pointer position 
    nextLine = fgetl(fid);    % Read the next line 
end 
fseek(fid,position,-1);    % Rewind to beginning of last line read 

% Read numerical data: 
nCol = sum(isspace(nextLine))+1;  % Get the number of columns 
data = fscanf(fid,'%i',[nCol inf]).'; % Note '%i' works for all integer formats 
fclose(fid);       % Close file 

Cela fonctionnera pour un nombre arbitraire de commentaires au début du fichier. Le calcul pour obtenir le nombre de colonnes a été inspiré par Jacob's answer.

+0

Et là je pensais que les textos pouvaient tout faire! – mtrw

+0

J'essaie d'éviter de définir explicitement le format, car mes fichiers peuvent avoir un nombre variable de colonnes. Bien sûr, si c'est ma seule option, je le ferai. Mais je trouve étrange que la charge échoue comme ça. – Kena

+0

Que faire si le nombre de lignes de commentaires et le nombre de colonnes n'est pas prédéterminé? – Kena

2

Nouveau:

C'est le meilleur que je pouvais trouver. Cela devrait fonctionner pour n'importe quel nombre de lignes de commentaires et de colonnes. Vous devrez faire le reste vous-même s'il y a des cordes, etc.

% Define the characters representing the start of the commented line 
% and the delimiter 
COMMENT_START = '%%'; 
DELIMITER = ' '; 

% Open the file 
fid = fopen('testMixed.txt'); 

% Read each line till we reach the data  
l = COMMENT_START; 
while(l(1)==COMMENT_START) 
    l = fgetl(fid); 
end 

% Compute the number of columns 
cols = sum(l==DELIMITER)+1; 
% Split the first line 
split_l = regexp(l,' ','split'); 

% Read all the data 
A = textscan(fid,'%s'); 
% Compute the number of rows 
rows = numel(A{:})/cols; 

% Close the file 
fclose(fid); 

% Assemble all the data into a matrix of cell strings 
DATA = [split_l ; reshape(A{:},[cols rows])']; %' adding this to make it pretty in SO 

% Recognize each column and process accordingly 
% by analyzing each element in the first row 
numeric_data = zeros(size(DATA)); 
for i=1:cols 
    str = DATA(1,i); 
    % If there is no '0x' present 
    if isempty(findstr(str{1},'0x')) == true 
     % This is a number 
     numeric_data(:,i) = str2num(char(DATA(:,i))); 
    else 
     % This is a hexadecimal number 
     col = char(DATA(:,i)); 
     numeric_data(:,i) = hex2dec(col(:,3:end)); 
    end 
end 

% Display the data 
format short g; 
disp(numeric_data) 

Cela fonctionne pour les données comme ceci:

% Comment 1 
% Comment 2 
1.2 0xc661 10 0xa661 
2 0xd661 20 0xb661 
3 0xe661 30 0xc661 

Sortie:

1.2  50785   10  42593 
    2  54881   20  46689 
    3  58977   30  50785 

VIEUX:

Ouais, je ne pense pas que LOAD est le moyen de aller. Vous pouvez essayer:

a = char(importdata('testHexa.txt')); 
a = hex2dec(a(:,3:end)); 
+0

Cela fonctionne pour les fichiers contenant uniquement des données hexadécimales, mais pas de données mixtes (voir entrée de fichier éditée ... J'ai plus de simplifié dans mon premier exemple) – Kena

+0

@Jacob, vous pouvez forcer textscan à traiter les commentaires avec: A = textcan (f, '% s', 'délimiteur', '\ n', 'MultipleDelimsAsOne', '1', 'CollectOutput', '1', 'CommentStyle', '%'); Cela gèrera également les commentaires au milieu du fichier. Pour le repos, je ne peux pas penser à quelque chose de plus élégant que ce que tu as déjà fait. – mtrw

+0

Merci! J'avais oublié ça en codant ça. – Jacob

2

Ceci est basé sur les deux années gnovice et les réponses de Jacob, et est un « meilleur de race »

Pour les fichiers comme:

% this is my comment 
% this is my other comment 

1 0xc661 123 
2 0xd661 456 
% surprise comment 
3 0xe661 789 
4 0xb661 1234567 

(où le nombre de colonnes dans le fichier DOIT être le même, mais pas connu à l'avance, et tous les commentaires dénotés par un caractère '%'), le code suivant est rapide et facile à lire:

f = fopen('hexdata.txt', 'rt'); 
A = textscan(f, '%s', 'Delimiter', '\n', 'MultipleDelimsAsOne', '1', 'CollectOutput', '1', 'CommentStyle', '%'); 
fclose(f); 
A = A{1}; 
data = sscanf(A{1}, '%i')'; 
data = repmat(data, length(A), 1); 
for ctr = 2:length(A) 
    data(ctr,:) = sscanf(A{ctr}, '%i')'; 
end 
+0

+1: Belle combinaison de réponses. Je me sens enclin à jouer une partie de "golf" avec vous et poster une réponse plus courte. ;) – gnovice