在Matlab中从命令行运行特定的单元格部分?

在Matlab中从命令行运行特定的单元格部分?,matlab,matlab-java,Matlab,Matlab Java,我正在用一个脚本(我们称之为foo.m)手动遍历Matlab中的各种单元格: 在Matlab的命令行中,我希望能够有选择地运行单元格2中的代码。只有如何交互操作的说明(例如,将光标放在适当的单元格中,然后诸如此类)。我想要一些命令行代码,这样我就可以像foo.runCell(1)一样运行上面单元格1中的代码 如果没有办法,我将把单元格分割成单独的脚本/函数。这不太方便,因为我正处于“非常快速地完成原型”的编码模式,所以现在希望所有东西都放在一个文件中。这是我的难看代码,符合您的要求 尽管我尽了最

我正在用一个脚本(我们称之为foo.m)手动遍历Matlab中的各种单元格:

在Matlab的命令行中,我希望能够有选择地运行单元格2中的代码。只有如何交互操作的说明(例如,将光标放在适当的单元格中,然后诸如此类)。我想要一些命令行代码,这样我就可以像foo.runCell(1)一样运行上面单元格1中的代码


如果没有办法,我将把单元格分割成单独的脚本/函数。这不太方便,因为我正处于“非常快速地完成原型”的编码模式,所以现在希望所有东西都放在一个文件中。

这是我的难看代码,符合您的要求

尽管我尽了最大的努力,我还是无法找到让它“正常”工作的方法(即不模拟按键)。我希望这将有助于其他人找到正确的方法。不管怎样,下面是:

运行代码部分infle.m

function runCodeSectionInFile(scriptFullPath,sectionNum)
%// TIP: You can use "which('scriptName')" to obtain the full path of a 
%// script on your MATLAB path.
%%% // Temporary Workaround
import java.awt.Robot;   %// part of temporary workaround
import java.awt.event.*; %// part of temporary workaround
RoboKey = Robot;         %// part of temporary workaround
RoboKey.setAutoDelay(10);%// part of temporary workaround
%% // Test if the needed components are available (optional)
if ~matlab.desktop.editor.isEditorAvailable || ...
   ~com.mathworks.mde.editor.codepad.Codepad.isCodepadEnabled
    error('MATLAB editor is N\A');
end
%% // Open and\or switch to the script file
%// Test if script is opened:
if ~matlab.desktop.editor.isOpen(scriptFullPath) 
    scriptDoc = matlab.desktop.editor.openDocument(scriptFullPath);
else %// in case the script is open, get a handle to it, and save it:
    scriptDoc = matlab.desktop.editor.findOpenDocument(scriptFullPath);
    %// Save the script before running (optional):
    scriptDoc.save;
end
scriptDoc.goToLine(0); %// Position the cursor at the beginning of the file
                       %// NOTE1: - uses zero based indexing!
jEd = com.mathworks.mlservices.MLEditorServices.getEditorApplication ...
        .openEditorForExistingFile(java.io.File(scriptFullPath));
jEd.getTextComponent.grabFocus; drawnow; %// part of temp fix
%// NOTE2: most of the above can be replaced with:
%//   EDITOROBJ = matlab.desktop.editor.openAndGoToLine(FILENAME,LINENUM);
%% // Get the Codepad and the LineManager handles:
jCm = com.mathworks.mde.editor.codepad.CodepadActionManager ...
                   .getCodepadActionManager(jEd);
jCp = jEd.getProperty('Codepad');
jLm = jCp.getLineManager(jEd.getTextComponent,jCm);
%% // Advance to the desired section
jAc = com.mathworks.mde.editor.codepad.CodepadAction.CODEPAD_NEXT_CELL;
                                           %// 'next-cell' Action

for ind1=1:sectionNum-1 %// click "advance" several times
    %// <somehowExecute(jAc) OR jCp.nextCell() >    
    RoboKey.keyPress(KeyEvent.VK_CONTROL); %// part of temporary workaround
    RoboKey.keyPress(KeyEvent.VK_DOWN);    %// part of temporary workaround
end
RoboKey.keyRelease(KeyEvent.VK_DOWN);      %// part of temporary workaround
RoboKey.keyRelease(KeyEvent.VK_CONTROL);   %// part of temporary workaround
%% Execute section - equivalent to clicking "Run Section" once

jAc = com.mathworks.mde.editor.codepad.CodepadAction.CODEPAD_EVALUATE_CELL; 
                                                 %// 'eval-cell' Action
%// <somehowExecute(jAc); OR jCp.evalCurrentCell(true) >    
RoboKey.keyPress(KeyEvent.VK_CONTROL); %// part of temporary workaround
RoboKey.keyPress(KeyEvent.VK_ENTER);   %// part of temporary workaround
RoboKey.keyRelease(KeyEvent.VK_CONTROL);   %// part of temporary workaround
%% // Close the file (optional)
jEd.close;
%% // Return focus to the command line:
com.mathworks.mde.cmdwin.CmdWin.getInstance.grabFocus;
%% // This is code block one
disp('This is section one');
%% // This is code block two
disp('This is section two');
%% // This is code block three
disp('This is section three');
要运行演示,只需将两个文件放在同一文件夹中,确保它位于您的路径(或cd)上,然后执行
runcodesectioninfle(其中('testScript.m'),1)
。其结果如下:

>> runCodeSectionInFile(which('testScript.m'),1)
This is section one
>> runCodeSectionInFile(which('testScript.m'),2)
This is section two
>> runCodeSectionInFile(which('testScript.m'),3)
This is section three
您可能还需要调整
RoboKey.setAutoDelay(10)设置为更大的数字

资料来源:

  • 附言。 这是我在2014b写的。其他(旧)版本可能需要调整

    编辑1:
    通过找到
    Codepad
    对象及其
    TaggedLineManager
    的句柄,我成功地揭开了这个谜团的另一部分。当前的问题是,大多数
    Codepad
    方法必须在EDT上运行(类似于“UI线程”,即源自与接口的交互)。

    Dev iL使用java等提供了一个很好的答案。。。这里我将提供一种替代方法,它不使用java或编辑器,而是在请求时读取文件并评估语句

    要使其工作,必须先保存文件(我知道这不是交互式运行单元格/代码块的先决条件)。

    不管怎样,我认为这是一个“古怪”的问题,我想我应该加上一个尝试的答案

    下面是我的脚本(cellScript.m),其中包含代码块(注意,我在“%%”之后为每个块指定了一个名称):

    我已经创建了一个类来完成所请求的作业(我称之为cellRunner.m)

    注意调用必须保存该文件才能使用

    样本运行:

    whos
    obj = cellRunner ( 'cellScript.m' );
    obj.runCell ( 'cellC' );
    running cell C
    past 1st coment
    past indented comment
    past block comment
    past multiple lines of comments
    finished cell C
    whos
      Name      Size             Bytes  Class         Attributes
    
      aa        1x100              800  double                  
      ans       1x1                112  cellRunner              
      ii        1x1                  8  double                  
      obj       1x1                112  cellRunner              
    

    注意1-为什么要使用句柄类?我从句柄类继承,因为我只需要已读取的文件数据的一个副本-有关何时使用值/句柄类的详细概述,请参阅。

    要使用命令行从文件运行特定节,可以使用

    echodemo(filename, index of section)
    

    如果有一种方法可以从命令行运行特定的代码段,我会感到惊讶。这样做的前提是您知道要运行的代码段的编号,而不必在面前的编辑器中打开文件……这很容易出错。一种更简洁的方法是定义函数;这样您就可以确切地知道您正在运行什么。当我处于与您相同的模式时,我只需为我的单元格设置非常明确的标题(您在双
    %%
    后面放置的文本将在编辑器中以粗体突出显示),然后我在控制台中键入/尝试的内容和执行完整单元格的编辑器之间进行混合。如果我得到一系列令我满意的命令,我只需将其(从命令历史记录中)拖到编辑器中,创建一个新单元格,给它起一个好名字,以便稍后轻松找到,然后继续下一段代码。您可能可以这样做(不知道怎么做)但这可能需要编写各种附加的辅助代码并深入研究MatlabGUI的操作。您可以使用for循环和条件语句(if…then或switch)相结合,就像在shell脚本中一样。这可能需要一点努力,但比通过深奥的matlab文档进行排序要少得多。@Jubobs是的,在我问题的最后一段中提到,可以选择将它们拆分为不同的函数/脚本。我试图避免这种情况,但这可能是最好的方法。我同意@TryHard-如果使用java gui函数可以实现这一点,我不会感到惊讶。不过,这可能需要您“模拟”打开文件,将光标移动到正确的单元格并单击“执行单元格”按钮。这在MATLAB gui中是一个不错的练习,但我怀疑它的有用性(因为Jubobs提到的原因)。我认为从一个函数中找到访问根工作区的方法或者在任何地方使用全局变量都会更容易(这两种方法听起来都像是坏主意,TBH)…我会给gui库看一看,以防你想要的不难…这确实是我建议的一个有趣的替代方案。顺便说一句,也许你应该解释一下为什么你扩展了
    句柄
    ,因为有些读者可能不太清楚…我添加了一个注释,说明了为什么我从句柄类继承。@matlabgui很好,而且有效。问题:初始值不应该吗调用类似于obj=cellRunner('filename.m')?是的,它应该是(我已经更新了答案)-最初的调用将运行我在测试时创建的默认值…@matlabgui它似乎挂起在某些注释行上(例如,如果
    %commet here
    位于独立行上,它将跳过文件的其余部分).我正在查看代码,看看是否可以修复它…效果很好,希望我能接受两个答案。处理评论非常顺利。
    classdef cellRunner < handle
      properties ( SetAccess = private )
        fileName
        fileInfo
        cellInfo
        cellNames = {};
      end
      methods 
        function obj = cellRunner ( file ) % constructor
          if nargin == 0                        
            obj.fileName = 'cellScript.m';      % default file for testing
          else
            obj.fileName = file;                % store user file
          end
          obj.parseFile();                      % read the file into memory
        end
        function obj = parseFile ( obj )
          if ~isempty ( obj.fileInfo )                        % on parsing check to see if its been parsed before
            if isequal ( obj.fileInfo, dir ( obj.fileName ) ) % Check date stamp (has cell file been modified
    %           disp ( 'file not changed - reading skipped' );  % if not skip
    %           reading 
              return
            end
          end
          obj.fileInfo = dir ( obj.fileName );                % store file info
          fid = fopen ( obj.fileName );                       % open file for reading
          if fid ~= -1
            index = 0;                                        % this is the index of each cell
            inCell = false;                                   % has it found a cell to start reading
            lines = cell(0);                                  
            while ( true )
              line = fgetl ( fid );                           % read the line in the file
              if line == -1; break; end                       % check for the end of the file
              sLine = strtrim ( line );                       % trim any white space
              if length ( sLine ) > 2 && strcmp ( sLine(1:2), '%%' ) % check to see if its the start of a cell
                if index > 0                                  % Store the last cell data                
                  obj.cellInfo{index} = lines;                % in class to run when required
                end
                index = index + 1;                            % increment the index
                obj.cellNames{index} = strtrim ( sLine(3:end) ); % save the name of the cell
                lines = cell(0);                              % re-initialise the lines var
                inCell = true;                                % the start of the cells have been found
              elseif inCell                                   % if reading a cell array
                lines{end+1} = line;                          % add each line to the lines var
              end          
            end
            if index > 0                                      % make sure and save the last cell when finished reading
              obj.cellInfo{index} = lines;
            end
            fclose ( fid );
          else
            error ( 'cellRunner:fileError', 'unable to read file' );
          end
        end
        function obj = runCell ( obj, arg )
          % obj.runCell ( 'cellName' );
          % obj.runCell ( index );
          obj.parseFile();                                    % check that the file hasn't been changed
          if ischar ( arg )                                   % if user provided a char then search for it
            index = strcmp ( arg, obj.cellNames );            % find the index
            if ~any ( index )                                 % check it was found
              error ( 'cellRunner:notFound', '%s not found', arg ); 
            end
          else
            index = arg;                                      % if index is an integer (not checked - assumed if not char)
            if index < 1 || index > length ( obj.cellInfo )   % check integer is valid
              error ( 'cellRunner:notFound', 'Index %d not found', arg );
            end
          end
          commands = obj.cellInfo{index}{1};                  % start to build the command to execute.
          inBlock = false;
          for ii=2:length(obj.cellInfo{index})                % loop around - ignoring any commented lines.
            nextLine = strtrim ( obj.cellInfo{index}{ii} ); 
            if inBlock
              if length ( nextLine ) == 2 && strcmp ( nextLine, '%}' );
                inBlock = false;
              end
              continue
            end
            if length ( nextLine ) == 2 && strcmp ( nextLine, '%{' );
              inBlock = true;
              continue
            end
            if length ( nextLine ) >= 1 && strcmp ( nextLine(1), '%' )
              continue;
            end
            commands = sprintf ( '%s;%s', commands, obj.cellInfo{index}{ii} ); % build a parge string to eval
          end
          evalin('base',commands);                            % eval the expression in the base workspace.
        end
      end
    end
    
    obj.cellRunner();
    % Individual cells can be run in two ways:
    
    % By providing the name of the cell (the string after the %%)
    obj.runCell ( 'cellC' );
    % By providing the index
    obj.runCell ( 3 );
    
    whos
    obj = cellRunner ( 'cellScript.m' );
    obj.runCell ( 'cellC' );
    running cell C
    past 1st coment
    past indented comment
    past block comment
    past multiple lines of comments
    finished cell C
    whos
      Name      Size             Bytes  Class         Attributes
    
      aa        1x100              800  double                  
      ans       1x1                112  cellRunner              
      ii        1x1                  8  double                  
      obj       1x1                112  cellRunner              
    
    echodemo(filename, index of section)