2010-07-14 31 views
11

Tôi đã thừa hưởng một số mã mà tác giả có sự hoài nghi với dấu chấm phẩy. Có thể sửa tất cả các tin nhắn mlint trong một lần (ít nhất là tất cả những cái có sửa lỗi tự động), thay vì phải bấm vào từng thông điệp và nhấn ALT + ENTER?Có cách nào để sửa tất cả các tin nhắn MATLAB mlint cùng một lúc không?

+3

Lưu ý rằng tôi đánh giá cao các câu trả lời hiện có, nhưng hy vọng tìm được giải pháp thường áp dụng hơn. –

+0

Họ đã thay thế mlint bằng mã kiểm tra gần đây. Bạn cũng có thể sử dụng nó. – NKN

Trả lời

8

LƯU Ý: Câu trả lời này sử dụng hàm MLINT, không còn được đề xuất trong các phiên bản MATLAB mới hơn. Chức năng mới hơn CHECKCODE được ưu tiên và mã bên dưới sẽ vẫn hoạt động bằng cách thay thế cuộc gọi thành MLINT bằng một cuộc gọi đến hàm mới hơn này.


Tôi không biết một cách nói chung để tự động sửa chữa mã dựa trên MLINT tin nhắn. Tuy nhiên, trong trường hợp cụ thể của bạn, có một cách tự động để bạn thêm dấu chấm phẩy vào các dòng để gửi cảnh báo MLINT.

Đầu tiên, chúng ta hãy bắt đầu với kịch bản mẫu này junk.m:

a = 1 
b = 2; 
c = 'a' 
d = [1 2 3] 
e = 'hello'; 

Các dòng đầu tiên, thứ ba, và thứ tư sẽ cung cấp cho bạn thông điệp MLINT cảnh báo "Chấm dứt tuyên bố với dấu chấm phẩy để ngăn chặn đầu ra (trong vòng một kịch bản). ". Sử dụng hình thức chức năng của MLINT, chúng tôi có thể tìm thấy các dòng trong tệp nơi cảnh báo này xảy ra. Sau đó, chúng ta có thể đọc tất cả các dòng mã từ tệp, thêm dấu chấm phẩy vào cuối dòng nơi cảnh báo xuất hiện và viết dòng mã trở lại tệp. Đây là mã để làm như vậy:

%# Find the lines where a given mlint warning occurs: 

fileName = 'junk.m'; 
mlintID = 'NOPTS';      %# The ID of the warning 
mlintData = mlint(fileName,'-id');  %# Run mlint on the file 
index = strcmp({mlintData.id},mlintID); %# Find occurrences of the warnings... 
lineNumbers = [mlintData(index).line]; %# ... and their line numbers 

%# Read the lines of code from the file: 

fid = fopen(fileName,'rt'); 
linesOfCode = textscan(fid,'%s','Delimiter',char(10)); %# Read each line 
fclose(fid); 

%# Modify the lines of code: 

linesOfCode = linesOfCode{1}; %# Remove the outer cell array encapsulation 
linesOfCode(lineNumbers) = strcat(linesOfCode(lineNumbers),';'); %# Add ';' 

%# Write the lines of code back to the file: 

fid = fopen(fileName,'wt'); 
fprintf(fid,'%s\n',linesOfCode{1:end-1}); %# Write all but the last line 
fprintf(fid,'%s',linesOfCode{end});  %# Write the last line 
fclose(fid); 

Và bây giờ, tệp junk.m phải có dấu chấm phẩy ở cuối mỗi dòng. Nếu bạn muốn, bạn có thể đặt mã ở trên vào một hàm để bạn có thể dễ dàng chạy nó trên mọi tệp của mã được kế thừa của bạn.

+1

Nếu bạn thay thế '-struct' bằng '-id' trong lời gọi của bạn thành mlint cấu trúc được trả về chứa một trường bổ sung được gọi là 'id' là một id ngắn cho thông báo mlint. Điều đó có thể dễ dàng hơn so với văn bản đầy đủ của tin nhắn. Cấu trúc này cũng chứa một trường có tên 'fix' là 0 cho tất cả các cảnh báo trong tệp thử nghiệm của tôi và tôi chưa tìm ra nó là gì - nó không được ghi chép. –

+0

@ Đánh dấu hiệu suất cao: Trường 'sửa' phải là một tính năng mới hơn, vì nó không xuất hiện trong MATLAB R2009a. – gnovice

+0

có, tôi đang chạy 2010a tại đây. –

6

Tôi biết đây là một bài đăng cũ nhưng tôi chỉ cần điều này gần đây và cải thiện một chút trên mã ban đầu vì vậy nếu ai khác cần nó ở đây nó được. Có vẻ thiếu ";" trong các hàm, không chỉ trong các tập lệnh thông thường, duy trì khoảng trắng trong mã và chỉ ghi các tệp có thay đổi.

function [] = add_semicolon(fileName) 
%# Find the lines where a given mlint warning occurs: 

mlintIDinScript = 'NOPTS';      %# The ID of the warning 
mlintIDinFunction = 'NOPRT'; 
mlintData = mlint(fileName,'-id');  %# Run mlint on the file 
index = strcmp({mlintData.id},mlintIDinScript) | strcmp({mlintData.id},mlintIDinFunction); %# Find occurrences of the warnings... 
lineNumbers = [mlintData(index).line]; %# ... and their line numbers 

if isempty(lineNumbers) 
    return; 
end; 
%# Read the lines of code from the file: 

fid = fopen(fileName,'rt'); 
%linesOfCode = textscan(fid,'%s', 'Whitespace', '\n\r'); %# Read each line 
lineNo = 0; 
tline = fgetl(fid); 
while ischar(tline) 
    lineNo = lineNo + 1; 
    linesOfCode{lineNo} = tline; 
    tline = fgetl(fid); 
end 
fclose(fid); 
%# Modify the lines of code: 

%linesOfCode = linesOfCode{1}; %# Remove the outer cell array encapsulation 
linesOfCode(lineNumbers) = strcat(linesOfCode(lineNumbers),';'); %# Add ';' 

%# Write the lines of code back to the file: 

fim = fopen(fileName,'wt'); 
fprintf(fim,'%s\n',linesOfCode{1:end-1}); %# Write all but the last line 
fprintf(fim,'%s',linesOfCode{end});  %# Write the last line 
fclose(fim); 
+1

Cảm ơn và chào mừng bạn đến với SO. Ngay cả những câu hỏi cũ đáng được thêm vào. –

7

Để giải quyết vấn đề này một cách tổng quát cho tất cả các tác vụ tự động sửa lỗi, chúng ta phải sử dụng các phương pháp java không có giấy tờ đầy đủ. Việc triển khai mlint (và bây giờ là checkcode) sử dụng mlintmex (nội trang dựng sẵn; không phải tên mexfile như tên cho thấy), chỉ trả lại kết quả văn bản từ linter. Không có các bản tự động bị phơi nhiễm; ngay cả số dòng và cột được phát ra dưới dạng văn bản thuần túy. Nó có vẻ giống như đầu ra từ nhị phân mlint trong cài đặt của Matlab ($(matlabroot)/bin/$(arch)/mlint)

Vì vậy, chúng ta phải quay trở lại bản triển khai java được sử dụng bởi chính trình soạn thảo. Cẩn thận: ở đây sau mã khủng khiếp không có giấy tờ cho R2013a.

%// Get the java component for the active matlab editor 
ed = matlab.desktop.editor.getActive().JavaEditor.getTextComponent(); 
%// Get the java representation of all mlint messages 
msgs = com.mathworks.widgets.text.mcode.MLint.getMessages(ed.getText(),ed.getFilename()) 

%// Loop through all messages and apply the autofix, if it exits 
%// Iterate backwards to try to prevent changing the location of subsequent 
%// fixes... but two nearby fixes could still mess each other up. 
for i = msgs.size-1:-1:0 
    if msgs.get(i).hasAutoFix() 
    com.mathworks.widgets.text.mcode.analyzer.CodeAnalyzerUtils.applyAutoFixes(ed,msgs.get(i).getAutoFixChanges); 
    end 
end 

EDIT:AHA! Bạn có thể nhận được số nhị phân mlint để trả về các bản sửa lỗi với cờ -fix ... và điều này cũng áp dụng cho nội dung dựng sẵn checkcode!Vẫn không có cơ sở (như xa như tôi biết), nhưng nhiều khả năng mạnh mẽ hơn nhiều so với ở trên:

>> checkcode(matlab.desktop.editor.getActiveFilename(),'-fix') 
L 2 (C 3): Terminate statement with semicolon to suppress output (in functions). (CAN FIX) 
----FIX MESSAGE <Add a semicolon.> 
----CHANGE MESSAGE L 2 (C 13); L 2 (C 12): <;> 
L 30 (C 52-53): Input argument 'in' might be unused. If this is OK, consider replacing it by ~. (CAN FIX) 
----FIX MESSAGE <Replace name by ~.> 
----CHANGE MESSAGE L 30 (C 52); L 30 (C 53): <~> 

Khi gán cho một cấu trúc, điều này cũng cho thấy mục đích của lĩnh vực mới fix rằng @High Performance Mark ghi chú trong bình luận của ông trên @gnovice 's answer; có vẻ như 1 khi có bản sửa lỗi, 2 khi thông báo là FIX MESSAGE ở trên và 4 khi thông báo là CHANGE MESSAGE.

Đây là hàm Matlab nhanh chóng và dơ bẩn trả về một chuỗi 'cố định' cho đường dẫn đến tệp m. Không có kiểm tra lỗi, vv, và nó không lưu các tập tin trở lại như tôi không hứa rằng nó sẽ làm việc. Bạn cũng có thể sử dụng API công cộng matlab.desktop.editor (!) Để nhận tài liệu hoạt động (getActive) và sử dụng trình lấy và đặt trên thuộc tính Text để sửa đổi tài liệu tại chỗ mà không lưu.

function str = applyAutoFixes(filepath) 

msgs = checkcode(filepath,'-fix'); 

fid = fopen(filepath,'rt'); 
iiLine = 1; 
lines = cell(0); 
line = fgets(fid); 
while ischar(line) 
    lines{iiLine} = line; 
    iiLine = iiLine+1; 
    line = fgets(fid); 
end 
fclose(fid); 

pos = [0 cumsum(cellfun('length',lines))]; 
str = [lines{:}]; 

fixes = msgs([msgs.fix] == 4); 
%// Iterate backwards to try to prevent changing the indexing of 'str' 
%// Note that two changes could still conflict with eachother. You could check 
%// for this, or iteratively run mlint and fix one problem at a time. 
for fix = fliplr(fixes(:)') 
    %'// fix.column is a 2x2 - not sure what the second column is used for 
    change_start = pos(fix.line(1)) + fix.column(1,1); 
    change_end = pos(fix.line(2)) + fix.column(2,1); 

    if change_start >= change_end 
     %// Seems to be an insertion 
     str = [str(1:change_start) fix.message str(change_start+1:end)]; 
    else 
     %// Seems to be a replacement 
     str = [str(1:change_start-1) fix.message str(change_end+1:end)]; 
    end 
end 
+0

Tuyệt vời, điều đầu tiên dường như chính xác là những gì tôi đang tìm kiếm! Sẽ không có cơ hội để kiểm tra nó trước khi tiền thưởng hết hạn, nhưng trừ khi ai đó có thể đầu này, nó đang đến theo cách của bạn. –

+2

Tôi đã thêm đánh giá Java vào một phím tắt, tìm thấy một biểu tượng công cụ tốt đẹp và nó chạy trơn tru cho đến nay. Giải pháp tuyệt vời. – Oleg

+0

@OlegKomarov: Xem ra, hai thay đổi trên cùng một dòng có thể gây rối lên. Tôi đã đảo ngược thứ tự lặp lại, mà dường như để sửa chữa hầu hết các trường hợp. Mạnh mẽ hơn, mặc dù, sẽ được lặp đi lặp lại chạy mlint và sửa chữa một tin nhắn tại một thời điểm. –

Các vấn đề liên quan