使用JavaScript删除空白行/列?

时间:2018-11-29 00:21:27

标签: javascript excel csv

我有一些JavaScript,它是.hta应用程序的一部分,可以将.xlsx电子表格转换为.csv文件。

如何确保在另存为过程中删除不包含数据的行/列,并且不将其作为导出的.csv文件的一部分出现?

下面是用于打开和保存文件的JS。

  // Open the workbook.
  var wb = xlApp.Workbooks.Open(aFile.Path);
  log('Successfully opened the file.');

  // Save each worksheet as a CSV file.
  var sheetNum = 0;
  for(var sheetIndex = 1, sheetCount = wb.Sheets.Count; sheetIndex <= sheetCount; sheetIndex++) {
    var ws = wb.Sheets.Item(sheetIndex);
    var wsName = ws.Name;

完整代码:

<script language="VBScript">
Function vbAlert(prompt, title, options)
  vbAlert = MsgBox(prompt, options, title)
End Function
</script>
<script type="text/JavaScript">
// Use VBScript's MsgBox for alert.
vbOKOnly = 0;
vbOKCancel = 1;
vbAbortRetryIgnore = 2;
vbYesNoCancel = 3;
vbYesNo = 4;
vbRetryCancel = 5;
vbCritical = 16;
vbQuestion = 32;
vbExclamation = 48;
vbInformation = 64;
vbDefaultButton1 = 0;
vbDefaultButton2 = 256;
vbDefaultButton3 = 512;
vbDefaultButton4 = 768;
vbOK = 1;
vbCancel = 2;
vbAbort = 3;
vbRetry = 4;
vbIgnore = 5;
vbYes = 6;
vbNo = 7;
function alert(prompt, title, options) {
  return vbAlert(
    prompt + '',
    (title == null ? document.title : title) + '',
    options == null ? vbExclamation : options
  );
}

// Used for file system access (reading and writing to files).
var fso = new ActiveXObject("Scripting.FileSystemObject");

// Used for browsing the file system for a folder by browseForFolder().
var shellApp = new ActiveXObject("Shell.Application");

// http://msdn.microsoft.com/en-us/library/windows/desktop/bb773205(v=vs.85).aspx
// Constants that may be used in the 3rd parameter of shellApp.BrowseForFolder:
var BIF_RETURNONLYFSDIRS = 0x1;
var BIF_DONTGOBELOWDOMAIN = 0x2;
var BIF_STATUSTEXT = 0x4;
var BIF_RETURNFSANCESTORS = 0x8;
var BIF_EDITBOX = 0x10;
var BIF_VALIDATE = 0x20;
var BIF_NEWDIALOGSTYLE = 0x40;
var BIF_BROWSEINCLUDEURLS = 0x80;
var BIF_UAHINT = 0x100;
var BIF_NONEWFOLDERBUTTON = 0x200;
var BIF_NOTRANSLATETARGETS = 0x400;
var BIF_BROWSEFORCOMPUTER = 0x1000;
var BIF_BROWSEFORPRINTER = 0x2000;
var BIF_BROWSEINCLUDEFILES = 0x4000;
var BIF_SHAREABLE = 0x8000;
var BIF_BROWSEFILEJUNCTIONS = 0x10000;

var xlNoChange = 1;
var xlCSV = 6;
var xlText = -4158;

/**
 * Regular expression to be used for verifying that the naming schema is valid.
 * @type {RegExp}
 */
var REGEXP_NAMING_SCHEMA = /<(WORKBOOK|SHEET|SHEET_NUMBER)>|[\\\/:\*\?"<>\|]/g;

/**
 * Regular expression used to collect all of the sheet filters.
 * @type {RegExp}
 */
var REGEXP_SHEET_FILTERS = /^(?:\/(.+)\/([gim]*)|.+)$/gm;

/**
 * Regular expression for matching filenames of the workbooks to be opened:
 * The first matching group captures the filename without the extension.
 * @type {RegExp}
 */
var REGEXP_WORKBOOK = /([^\\\/]+)\.xlsx?$/i;

// Retrieves an element by ID.
function $id(id) {
  return document.getElementById(id);
}

(function(_, g, u) {
  typeOf = function(o, p) {
    o = o === g
      ? "global"
      : o == u
        ? o === u
          ? "undefined"
          : "null"
        : _.toString.call(o).slice(8, -1);
    return p ? p === o : o;
  };
})({}, this);

// Function to add a number's (ordinal).
(function(o) {
  Number.getOrdinalFor = function(intNum, includeNumber) {
    return (includeNumber ? intNum : "")
      + (o[((intNum = Math.abs(intNum % 100)) - 20) % 10] || o[intNum] || "th");
  };
})([,"st","nd","rd"]);

// Opens a dialog box which allows the user to browse for a folder.
function browseForFolder() {
  try {
    // Let the user select a folder.  Documentation for this function is here:
    // http://msdn.microsoft.com/en-us/library/windows/desktop/bb774065(v=vs.85).aspx
    var folder = shellApp.BrowseForFolder(
      0, // Hwnd
      'Select the desired folder:', // sTitle
      BIF_RETURNONLYFSDIRS | BIF_UAHINT | BIF_NONEWFOLDERBUTTON // iOptions
    );

    // If the user selected a user...
    if(folder) {
      var folderPath = folder.Self.Path;
      $id('txtFolder').value = folderPath;
    }
  }
  catch(e) {
    alert('The following error occurred:\r\n' + e.message, 'Error');
  }
}

// Takes user to my website.
function showAbout() {
  var hta = $id('hta');
  var appName = hta.applicationName;
  var version = hta.version;
  var message = appName + ' v' + version + '\n\n' +
    'Created by Christopher West\n' + 'Copyright \u00A9 2013\n\n' +
    'Would you like to visit my site?';
  var title = 'About This Application';
  var response = alert(message, title, vbYesNo + vbInformation);
  if(response == vbYes) {
    (new ActiveXObject("WScript.Shell")).Run('http://cwestblog.com/');
  }
}

// Closes this window.
function closeWindow() {
  window.close();
}

// Adds the mask to the page, showing the mask content.
function addMask() {
  document.body.className = 'masked';
}

// Removes the mask from the page, hiding the mask content.
function removeMask() {
  document.body.className = '';
}

// Opens the console, clearing out the old data.
function openConsole() {
  $id('divConsole').innerHTML = '';
  addMask();
  return logInConsole;
}

function logInConsole(msg) {
  var divConsole = $id('divConsole');
  var div = document.createElement('DIV')
  div.className = divConsole.getElementsByTagName('DIV').length % 2
    ? 'even'
    : 'odd';
  div.innerText = msg;
  divConsole.appendChild(div);
}

// Close the console by removing the mask.
function closeConsole() {
  removeMask();
}

/**
 * Verify that all of the inputs are good.
 * @returns {?Object}
 *     Returns an object literal with all of the input data if all of the inputs
 *     are good.  Otherwise nothing is returned.
 */
function verifyInputs() {
  var errors = [];

  // Make sure the folder was selected.
  var path = $id('txtFolder').value;
  if(!path) {
    errors.push('Folder - No folder was selected.');
  }

  // Make sure the naming schema is given and that it is valid.
  var namingSchema = $id('txtNamingSchema').value;
  if(!namingSchema) {
    errors.push('CSV Naming Schema - No naming schema was given.');
  }
  else {
    namingSchema.replace(REGEXP_NAMING_SCHEMA, function(match, id, index) {
      if(!id) {
        errors.push('CSV Naming Schema - The ' + Number.getOrdinalFor(index + 1, true) +
          ' character is ' + match + ' which is not allowed in filenames.'
        );
      }
    });
  }

  // Get all of the sheet filters, making sure the ones that are regular
  // expressions are actually valid.
  var filters = [];
  var strFilters = $id('txtSheetFilters').value;
  strFilters.replace(REGEXP_SHEET_FILTERS, function(match, pattern, flags) {
    if(pattern) {
      try {
        filters.push(new RegExp(pattern, flags));
      }
      catch(e) {
        errors.push('Sheet Filters - "' + match +
          '" is an invalid sheet filter RegExp because of the following:  ' +
          e.message
        );
      }
    }
    else {
      filters.push(match);
    }
  });

  if(!errors.length) {
    return {
      path: path,
      namingSchema: namingSchema,
      filters: filters,
      noLineFeeds: $id('chkNoLineFeeds').checked
    };
  }

  alert('The following error' + (1 in errors ? 's' : '') +
      ' occurred:\n- ' + errors.join('\n- '),
    'Error'
  );
}

// Converts the workbooks into CSVs.
function startConverting() {
  // If one or more of the inputs is missing or invalid, don't go any further.
  var inputs = verifyInputs();
  if(!inputs) {
    return;
  }
  var filters = inputs.filters;

  // Fire up the console.
  var log = openConsole();

  try {
    // Create an instance of Excel, but don't allow the content
    // area to be repainted.
    log('Starting up Excel...');
    var xlApp = new ActiveXObject("Excel.Application");
    xlApp.Visible = false;
    xlApp.ScreenUpdating = false;
    xlApp.DisplayAlerts = false;
    log('Opened, hid and silenced Excel.');

    // Initialize the counts.
    var fileCount = 0, csvCount = 0;

    // Reference the containing folder.
    log('About to verify the existence of "' + inputs.path + '".');
    var fldr = fso.GetFolder(inputs.path);

    var delimiter = !$id('radDelimComma').checked
      ? $id('radDelimTab').checked
        ? '\t'
        : ';'
      : ',';
    var outputType = delimiter == '\t' ? 'TSV' : 'CSV';

    var DecimalSeparator = xlApp.DecimalSeparator;
    var ThousandsSeparator = xlApp.ThousandsSeparator;
    var UseSystemSeparators = xlApp.UseSystemSeparators;

    try {

      if(delimiter != '\t') {
        xlApp.DecimalSeparator = delimiter == ';' ? ',' : '.';
        xlApp.ThousandsSeparator = delimiter == ';' ? '.' : ',';
        xlApp.UseSystemSeparators = false;
      }

      // Loop through all of the xls and xlsx files in this folder.
      for(var e = new Enumerator(fldr.Files); !e.atEnd(); e.moveNext()) {
        var aFile = e.item();
        if(REGEXP_WORKBOOK.test(aFile.Name)) {
          log('Opening "' + aFile.Path + '"...');

          // Open the workbook.
          var wb = xlApp.Workbooks.Open(aFile.Path);
          log('Successfully opened the file.');

          // Save each worksheet as a CSV file.
          var sheetNum = 0;
          for(var sheetIndex = 1, sheetCount = wb.Sheets.Count; sheetIndex <= sheetCount; sheetIndex++) {
            var ws = wb.Sheets.Item(sheetIndex);
            var wsName = ws.Name;

            // If this worksheet isn't visible don't use it nor even count it.
            if(!ws.Visible) {
              continue;
            }

            // Increment the sheet number so that it can be used in the file name.
            sheetNum++;


            // If filters were specified, filter out sheets that don't match them.
            var keepGoing = !filters.length, filter;
            for(var i = 0; !keepGoing && i < filters.length; i++) {
              keepGoing = keepGoing ||
                (typeOf(filter = filters[i], 'RegExp')
                  ? filter.test(wsName)
                  : filter == wsName
                );
            }
            if(!keepGoing) {
              log('Skipping "' + wsName + '" (sheet #' + sheetNum +
                ") because it didn't pass the filters."); 
              continue;
            }

            // If no line feeds should appear, remove them all.
            if(inputs.noLineFeeds) {
              ws.UsedRange.Replace("\n", "");
            }

            // Save the file using the naming schema.
            var csvPath = aFile.Path.replace(REGEXP_WORKBOOK, function(filename, workbookName) {
              return inputs.namingSchema.replace(REGEXP_NAMING_SCHEMA, function(match, part) {
                return part != 'WORKBOOK'
                  ? part != 'SHEET'
                    ? sheetNum
                    : wsName
                  : workbookName;
              });
            });

            log('New ' + outputType + ' will be saved at "' + csvPath + '"...');
            ws.Activate();
            wb.SaveAs(
              csvPath, // Filename
              delimiter == '\t' ? xlText : xlCSV, // FileFormat
              null, // Password
              null, // WriteResPassword
              null, // ReadOnlyRecommend
              false, // CreateBackup
              xlNoChange, // AccessMode
              null, // ConflictResolution
              null, // AddToMru
              null, // TextCodepage
              null, // TextVisualLayout
              true // Local
            );
            log('Saved the ' + outputType + ' successfully.');
            csvCount++;  // Increment the number of CSV's.
          }

          // Close the workbook.
          wb.Close();
          log('Closed the workbook.');

          // Increment the number of files.
          fileCount++;
        }
      }
    }
    catch(e) {
      throw e;
    }
    finally {
      xlApp.DecimalSeparator = DecimalSeparator;
      xlApp.ThousandsSeparator = ThousandsSeparator;
      xlApp.UseSystemSeparators = UseSystemSeparators;
    }

    // Allow alerts to be displayed, and the screen to be updated again.
    xlApp.DisplayAlerts = true;
    xlApp.ScreenUpdating = true;

    // Close Excel.
    xlApp.Quit();

    var msg = "The results are as follows:\nFiles converted:  "
      + fileCount + "\n" + outputType + "'s created:  " + csvCount;
    var title = "Conversion Process Complete";
    alert(msg, title, vbInformation);
  }
  catch(e) {
    // If the Excel workbook is open, close it.
    try{ wb.Close(false); }catch(e2){}

    // If Excel is open, change the settings back to normal and close it.
    try{
      xlApp.DisplayAlerts = true;
      xlApp.ScreenUpdating = true;
      xlApp.Quit();
    } catch(e2){}

    // Print the error message.
    var msg = "The following error caused this script to fail:\n"
      + e.message + '\n' + e.lineNumber;
    var title = "Critical Error Occurred";
    alert(msg, title, vbCritical);
  }
}

// Make the window the right size.
window.resizeTo(1000, 765);

// Once the page loads, bind all of button click events.
window.onload = function() {
  $id('btnBrowseFolder').onclick = browseForFolder;
  $id('btnAboutThisApp').onclick = showAbout;
  $id('btnClose').onclick = closeWindow;
  $id('btnStart').onclick = startConverting;
  $id('btnCloseConsole').onclick = closeConsole;
};
</script>

1 个答案:

答案 0 :(得分:0)

未经测试,请尝试以下方法:

for(var sheetIndex = 1, sheetCount = wb.Sheets.Count; sheetIndex <= sheetCount; sheetIndex++) {

    var ws = wb.Sheets.Item(sheetIndex);
    var wsName = ws.Name;
    var usedRng = ws.UsedRange;

    for(var i = usedRng.Rows.Count; i > 0; i--){
        if( xlApp.CountA(usedRng.Rows(i)) == 0 ) usedRng.Rows(i).Delete();
    }

    for(var i = usedRng.Columns.Count; i > 0; i--){
        if( xlApp.CountA(usedRng.Columns(i)) == 0 ) usedRng.Columns(i).Delete();
    }

编辑:

  1. 要替换内容,可以使用Range.Replace方法。

例如:

ws.UsedRange.Replace("Monday", "Friday"); //check the other optional parameters...

https://docs.microsoft.com/en-us/office/vba/api/excel.range.replace

  1. 为什么要重新导入CSV文件而不是将每张工作表复制到新的工作簿中?