Search code examples
google-apps-scriptgoogle-sheetsreplacerangereplaceall

What is the most efficient way of finding and replacing multiple strings of a cell in a range?


**Background **

  • I am working on a code for making combos in a fighting game
  • I need to take a range, then convert certain numbers and/or letters into other Numbers/and/or letters with additional characters/spacing so the program registers the combo.

Right now I have some code that gets the job done but I don't believe this is the "right" nor efficient way to do this since In all there will be about 40 "switches" to be set up:

 function printCombo()  {
//general set up
  const ss=SpreadsheetApp.getActive();
  const psh=ss.getSheetByName('Print Sheet');
  const scanrange= psh.getRange("Range to be scanned");

//set constants and text they are being replaced with
  const 1A = scanrange.createTextFinder('1A');
  1A.replaceAllWith('1 A');
  const 2B = scanrange.createTextFinder('2B');
  2B..replaceAllWith('2   B');
  const 3C = scanrange.createTextFinder('3C');
  3C.replaceAllWith('');
  const 4D = scanrange.createTextFinder('4D');
  4D.replaceAllWith('4 ]D[ 4');
  const xy = scanrange.createTextFinder('xy');
  4D.replaceAllWith('xy's replacement');
}

Also, if there are any beginner guides around this sort of subject, please let me know, as I'm still a touch and go beginner when it comes to the logic of script coding and order of operations

Thanks!!

Bonus Question: Is there a way to make it so that if a cell is "Bold"/ some other form of styling, it places a ][ around whatever character of that cell is bolded? for example "3B" would become "3 ]B[" instead of "3 B" <= this would be the end game of this replacement process, and make me have to list less switches, but if that's too complicated then no worries.


Solution

  • I believe your goal as follows.

    • You want to reduce the process cost of your script.
    • In your situation, you want to replace the texts with about 40 patterns.

    Modification points:

    • I think that the variables of const 1A =, const 2B = and so on cannot be used. Please be careful this.
    • About 4D.replaceAllWith('xy's replacement');, in this case, xy's replacement is not enclosed. Please be careful this.
    • About 2B..replaceAllWith('2 B');, .. is not correct.
    • In order to reduce the process cost of your script, in this answer, I would like to propose to use Sheets API. When the Sheets API is used, replacing the texts with about 40 patterns can be done by one API call. By this, I thought that the process cost will be able to be reduced.

    When above points are reflected to your script, it becomes as follows.

    Modified script:

    Before you use this script, please enable Sheets API at Advanced Google services.

    function printCombo() {
      //general set up
      const ss = SpreadsheetApp.getActive();
      const psh=ss.getSheetByName('Print Sheet');
      const scanrange= psh.getRange("Range to be scanned");
    
      // I modified below script.
      // Please set the replace patterns for this object. This object uses your patterns.
      const replacePatterns = [
        { search: '1A', replace: '1 A' },
        { search: '2B', replace: '2   B' },
        { search: '3C', replace: '' },
        { search: '4D', replace: '4 ]D[ 4' },
        { search: 'xy', replace: "xy's replacement" }
      ];
      const sheetId = psh.getSheetId();
      const startRowIndex = scanrange.getRow() - 1;
      const endRowIndex = startRowIndex + scanrange.getNumRows();
      const startColumnIndex = scanrange.getColumn() - 1;
      const endColumnIndex = startColumnIndex + scanrange.getNumColumns();
      const requests = replacePatterns.map(({ search, replace }) => ({ findReplace: { range: { sheetId: sheetId, startRowIndex: startRowIndex, endRowIndex: endRowIndex, startColumnIndex: startColumnIndex, endColumnIndex: endColumnIndex }, find: search, replacement: replace } }));
      Sheets.Spreadsheets.batchUpdate({ requests: requests }, ss.getId());
    }
    
    • When above script is run, the cell values of scanrange are replaced using the replace patterns of replacePatterns.

    Note:

    • About your Bonus Question, in that case, I think that the other process from above modification might be required to be used. So in this case, I would like to recommend to post it as new question.

    References:

    Added:

    From your following replying,

    this is an awesome solve, however with this being a script that I would need to be able for people to quickly understand and use, is there any way to do this sort of setup without activating the advanced sheets API situation?

    How about the following sample script?

    function printCombo() {
      //general set up
      const ss = SpreadsheetApp.getActive();
      const psh=ss.getSheetByName('Print Sheet');
      const scanrange= psh.getRange("Range to be scanned");
    
      // I modified below script.
      // Please set the replace patterns for this object. This object uses your patterns.
      const replacePatterns = [
        { search: '1A', replace: '1 A' },
        { search: '2B', replace: '2   B' },
        { search: '3C', replace: '' },
        { search: '4D', replace: '4 ]D[ 4' },
        { search: 'xy', replace: "xy's replacement" }
      ];
      replacePatterns.forEach(({ search, replace }) => scanrange.createTextFinder(search).replaceAllWith(replace));
    }