remove-whitespaces.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. #
  4. # 2014, By konstin (http://github/konstin)
  5. # 2015, Modified by leyyin
  6. #
  7. # Removes all trailing whitespaces and replaces all tabs with four spaces, the
  8. # files with a given extension in a recursively searched directory.
  9. # It can also count the number of code lines excluding comments and blank
  10. # lines.
  11. #
  12. # Tested with python 2.7 and python 3
  13. import os
  14. import argparse
  15. import sys
  16. def main(directory, is_statistics, is_dry_run, extensions, comments_start):
  17. lines_total = 0
  18. lines_comments = 0
  19. file_counter = 0
  20. files_affected = 0
  21. for dir_path, _, file_names in os.walk(directory):
  22. if is_statistics:
  23. file_counter += len(file_names)
  24. for file_name in file_names:
  25. _, file_extension = os.path.splitext(file_name)
  26. # File does not have an extension
  27. if not file_extension:
  28. continue
  29. # Not a valid extension. Note: extensions have in the 0 position a dot, eg: '.hpp', '.cpp'
  30. if file_extension[1:] not in extensions:
  31. continue
  32. if is_statistics:
  33. files_affected += 1
  34. # Read whole file
  35. path_file = os.path.join(dir_path, file_name)
  36. with open(path_file, 'r') as f:
  37. lines = f.readlines()
  38. if is_statistics:
  39. lines_total += len(lines)
  40. # Scan lines
  41. is_modified = False
  42. for i, line in enumerate(lines):
  43. original_line = line
  44. # Replace tabs with four spaces
  45. line = line.replace('\t', ' ')
  46. line_rstrip = line.rstrip()
  47. if line_rstrip: # Don't de-indent empty lines
  48. line = line_rstrip + '\n'
  49. # Count the number of comments
  50. if is_statistics:
  51. line_lstrip = line.lstrip()
  52. if any([line_lstrip.startswith(c) for c in comments_start]):
  53. lines_comments += 1
  54. # Indicate that we want to write to the current file
  55. if original_line != line:
  56. lines[i] = line # Replace original line
  57. if not is_modified:
  58. is_modified = True
  59. # Write back modified lines
  60. if not is_dry_run and is_modified:
  61. with open(path_file, 'w') as f:
  62. f.writelines(lines)
  63. if is_statistics:
  64. print('Total number of files in {0}: {1}'.format(directory, file_counter))
  65. print('Total number of files affected in {0}: {1}'.format(directory, files_affected))
  66. print('Lines in total: {0}'.format(lines_total))
  67. print(' empty/comments: {0}'.format(lines_comments))
  68. print('↳ excluding comments and blank lines: {0}'.format(lines_total - lines_comments), end='\n' * 2)
  69. print('Finished.')
  70. if __name__ == '__main__':
  71. parser = argparse.ArgumentParser(description='Remove whitespace from C/C++ files.')
  72. parser.add_argument('directory', default='../src', nargs='?',
  73. help='the directory where all the source files are located. (default: %(default)s)')
  74. parser.add_argument('--dry-run', dest='dry_run', action='store_true',
  75. help='do a dry run. Do not modify/write any files. (default: %(default)s)')
  76. parser.add_argument('--statistics', dest='statistics', action='store_true',
  77. help='display statistics (count files and lines if enabled). On by default.')
  78. parser.add_argument('--no-statistics', dest='statistics', action='store_false', help='do not display statistics.')
  79. parser.add_argument('--extensions', default=["cpp", "hpp", "c", "h"], nargs='+',
  80. help='set file extensions. Eg: --extensions cpp hpp (default: %(default)s).')
  81. parser.add_argument('--comments-start', default=['//', '/*', '*'], nargs='+',
  82. help='set how line comments start. Eg: --comments-start // \'*\'. (default: %(default)s).')
  83. parser.set_defaults(statistics=True)
  84. parser.set_defaults(dry_run=False)
  85. args = parser.parse_args()
  86. if not os.path.exists(args.directory):
  87. print('ERROR: The directory {0} does not exist'.format(args.directory))
  88. sys.exit(1)
  89. print(args)
  90. main(args.directory, args.statistics, args.dry_run, args.extensions, args.comments_start)