Как я могу подсчитать количество строк фактических комментариев?

У меня есть куча файлов скриптов/функций MATLAB, над которыми мне и моей команде нужно поработать. Мы практически не знаем, что делает большинство файлов, и практически не знаем, какие из них принадлежат друг другу, а какие — по отдельности. Мы знаем, что у нас всего 36 000 строк. Я хотел бы знать, сколько из этих строк являются комментариями.

Легко, верно? Просто подсчитайте, сколько из них начинаются с начального символа комментария %.

Ну нет. Я не хочу считать закомментированные блоки кода «комментариями», так как они на самом деле мне ничего не говорят. И я бы предпочел не считать «пустые» строки, используемые для того, чтобы сделать одну строку комментария «заголовком».

% %%%%%%%%
% headline
% %%%%%%%%

вот так.

Итак, как я могу получить разумную оценку того, сколько строк фактических информативных комментариев у меня есть? Есть ли простой способ отличить естественный язык (возможно, содержащий фрагменты кода) от чистого кода?


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


person gibson    schedule 07.11.2018    source источник
comment
Я предполагаю, что вы всегда можете поймать все, что начинается с % и regexp, чтобы поймать те, которые сделаны чем-то другим, чем просто символы %.   -  person Ander Biguri    schedule 07.11.2018
comment
Как насчет блоков комментариев (%{ .... %})?   -  person Dev-iL    schedule 07.11.2018
comment
Вам нужно четко определить, какие строки или комбинации вы хотите исключить, что, если я напишу % === или % % % % % или % ------- %, а не полезный раздел, определяющий комментарии, такие как %% Heading? Из этого описания неясно, какие комментарии вас интересуют.   -  person Wolfie    schedule 07.11.2018
comment
Отлавливать комментарии легко, и отлавливать несколько очевидных особых случаев, таких как примеры из @Wolfie, также довольно легко. Я спрашиваю о разумной эвристике/регулярных выражениях, чтобы увидеть разницу между % useful text и % for i = length(variable):size(gizmos). К счастью, @Dev-iL, в коде нет блочных комментариев такого типа.   -  person gibson    schedule 07.11.2018
comment
Вы можете использовать мое решение, чтобы получить, какие строки являются технически кодом, а какие технически комментариями, и, возможно, собрать все это в каком-то файле журнала, но определить, сколько из них являются настоящие комментарии будут сложной задачей, возможно, с использованием машинного обучения, которое, вероятно, выходит за рамки одного вопроса SO.   -  person Dev-iL    schedule 07.11.2018
comment
@gibson, последнее, смирись с тем, что ты не сможешь добиться этого автоматически. это требует не только человеческого уровня понимания, но и человека-эксперта на уровне возможностей анализа MATLAB.   -  person Ander Biguri    schedule 07.11.2018


Ответы (3)


Для этого мы можем использовать полудокументированную утилиту mtree.

Возьмем, к примеру, файл .m, содержащий определение самого класса mtree.

dbtype mtree дает (это только начало):

1     classdef mtree
2     %MTREE  Create and manipulate M parse trees
3     %   This is an experimental program whose behavior and interface is likely
4     %   to change in the future.
5     
6     % Copyright 2006-2016 The MathWorks, Inc.
7     
8         properties (SetAccess='protected', GetAccess='protected', Hidden)
9             T    % parse tree array

Теперь, если мы вызовем утилиту mtree на себя и покажем результат в виде текста,

tree = mtree('mtree.m','-file');
tree.dumptree()

вот что мы получаем (опять же, только начало):

  1  *:  CLASSDEF:   1/01 
  3     *Cexpr:  ID:   1/10  (mtree)
  4     *Body:  PROPERTIES:   8/05 
  5        *Attr:  ATTRIBUTES:   8/16 
  6           *Arg:  ATTR:   8/26 
  7              *Left:  ID:   8/17  (SetAccess)
  8              *Right:  CHARVECTOR:   8/27  ('protected')
  9           >Next:  ATTR:   8/49 
 10              *Left:  ID:   8/40  (GetAccess)
 11              *Right:  CHARVECTOR:   8/50  ('protected')
 12           >Next:  ATTR:   8/63 
 13              *Left:  ID:   8/63  (Hidden)
 14        *Body:  EQUALS:   9/09 

Как видно из приведенного выше, комментарий и пустые строки (2-7) не отображаются слева от «дробей» в выводе. Поэтому, если мы найдем способ получить «числители», мы получить номера строк, содержащих фактический код.

Нам повезло, так как существует метод, который дает нам эти числители - lineno! Поэтому, если мы вызовем его и применим к выводу unique, мы получим ровно одну копию каждой строки:

uLines = unique(tree.lineno);
nCodeLines = numel(uLines);

Это дает значение 269 для nCodeLines в R2018b. Если вы готовы предположить, что последняя строка в файле всегда является строкой кода (а не комментарием или пробелом), вы можете просто вычесть nCodeLines из последнего элемента uLines, чтобы получить количество строк комментариев (121 в этом случае). В противном случае используйте другой метод для подсчета общего количества строк (пример).

Осталось написать это как функцию и скормить ей папку .m файлов :)

person Dev-iL    schedule 07.11.2018
comment
Я думаю, что это решает неправильную проблему. Я уже могу сосчитать количество строк, не являющихся комментариями. Я хочу подсчитать среди закомментированных строк, какие из них являются информативным текстом, а какие представляют собой код, которому предшествует %. Возможно, я мог бы использовать этот метод в строках, начинающихся с %, если я удалю первый символ.... - person gibson; 07.11.2018
comment
@gibson Интересная идея. В любом случае, то, что у вас есть, это не столько проблема подсчета, сколько проблема распознавания (подсчет тривиален, если вы знаете, что считать). Я бы посоветовал вам вытащить все строки комментариев, затем вручную пройтись по первым сотням и посмотреть, сколько из них реальных комментариев, а сколько закомментированного кода — чтобы установить некую меру плотности качественных комментариев. Затем умножьте на количество строк комментариев. Поскольку все, что вам нужно, это оценка, чем больше строк вы включите в оценку плотности, тем точнее будет конечный результат. - person Dev-iL; 07.11.2018
comment
Я просмотрел первые пару сотен строк комментариев, но все они были кодом с % впереди. Но я также видел по крайней мере один файл только с правильными комментариями. Вероятно, мне следует рандомизировать их порядок, чтобы я мог получить полезную оценку, возможно, из 100 строк. - person gibson; 07.11.2018
comment
(и в качестве продолжения моей идеи использовать подход mtree к закомментированным строкам: mtree, похоже, не различает исполняемые строки и строки с ошибками, поэтому % the for loop is a = 1:length(gizmos) instead of :length(widgets) because bla bla будет считаться кодом после удаления %) - person gibson; 07.11.2018
comment
Вероятно, есть более разумный способ анализа mtree, который мог бы решить эту проблему, но я недостаточно знаком с mtree, чтобы комментировать дальше. - person Dev-iL; 07.11.2018

Легко получить комментарии, которые не просто разделяют вещи, исключая все, что не содержит текста: az или AZ. Таким образом, %a является «информативным комментарием», а %----- нет.

Теперь, чтобы отфильтровать код, я считаю, что лучше всего рассматривать %text text как комментарий, а остальное как код: комментарий — это место, где есть пробел между двумя фрагментами текста. Фрагмент текста может быть чем угодно, что содержит букву, или он может быть ограничен элементами, состоящими только из букв и знаков препинания (в одном случае a=5 — это отдельный фрагмент текста, в другом — это отдельный фрагмент, не являющийся текстом), и вы также должны исключить зарезервированные кодовые слова.

Это, очевидно, не будет работать все время, поскольку текст, содержащий только одно слово, также является информативным комментарием, скажем, у вас может быть комментарий, говорящий %randomize. Однако учтите следующее: randomize может быть комментарием, говорящим о том, что приведенный ниже материал выполняет рандомизацию (скорее всего), или это может быть функция, которая выполняет рандомизацию без каких-либо параметров и выдачи каких-либо результатов (например, злоупотребляя отражением, чтобы действительно что-то сделать). Невозможно разобрать эти два варианта — синтаксический анализатор должен будет запускать код построчно и проверять, работает ли эта строка как-либо или выдает ошибку для работы в таких сценариях.

Обратите внимание, что код не будет работать напрямую и не является оптимальным, но исправить его должно быть достаточно просто.

isC = parseComment(commentText)
splitText = split(commentText, ' '); % split by whitespace.
isValidText = false(length(splitText),1);
if (length(isValidText) == 1)
   isC = false;
   return
end
for i=1:length(splitText)
   % find if this "word" is valid non-code text.
   if (contains(splitText(i), [a-z])) % Fix this condition, should suitably check if the thingy is a word in a way you want it.
      if ~isReservedCodeWord(splitText(i)) % here you should exclude if, for, while and so on.
         isValidText(i) = true;
      end
   end
end
%checking of parts is complete, check if the string has 2 adjacent "valid text" parts.
isC = any(isValidText(1:end-1) & isValidText(2:end));
person Zizy Archer    schedule 07.11.2018

Отвечая на мой собственный вопрос здесь, так как я пошел в другом направлении, чем любой из ответов.


Мне нужна была оценка, не обязательно точное число. Меня бы устроила автоматизированная система, даже если бы она неправильно классифицировала некоторые строки. Но я не смог найти достаточно простого способа отличить код от текста, поэтому я пошел более ручным путем.

Я просто grep отредактировал все строки комментариев, а затем перемешал порядок строк вывода, чтобы я мог просмотреть последние 50 или около того строк на своем экране и вручную подсчитать соотношение полезных комментариев к прокомментированному коду. Это дает мне приблизительную оценку, а умножая ее на количество строк комментариев, я получаю оценку количества полезных строк комментариев.

Вывод таков, что у нас есть около 36000 строк почти полностью недокументированного кода, с которым можно поиграться. Ура.

Чтобы изменить порядок строк, я использовал файл shuffle.bat, который нашел здесь Как произвольно изменить порядок строк в текстовом файле с помощью пакетного файла

Так что я остановился на type *.m | grep % | shuffle.bat

И этого было достаточно для меня.


Предложение Dev-il использовать mtree было бы очень полезным, если бы mtree можно было заставить выводить количество строк анализируемого, исполняемого кода. Затем я мог бы grep удалить строки комментариев, убрать % в начале, а затем использовать mtree для подсчета того, что является исполняемым кодом, а что, скорее всего, текстом. К сожалению, mtree будет анализировать что угодно и на самом деле не различает то, что в конечном итоге имеет смысл как код, и то, что не имеет смысла.

person gibson    schedule 08.11.2018