简体   繁体   中英

Google Script 'replace' function with range

I'm trying to script a "roman-number-to-decimal-number" function in Google Spreadsheets. So far I've managed to make it work using the code below:

function rom2num(inputRange) {
inputRange = inputRange.replace(/\bi\b/gi,1); //convert 'I' to '1'
  return inputRange;
}

This works perfectly when the input is one cell only. However, whenever I try to input a range (A1:B2) I get the error: "cannot find function replace in object".

Some examples of what I want to achieve:

Column A      | Column with function
i, ii, iii    | 1, 2, 3
Godfather II  | Godfather 2
iv, v, vi     | 4, 5, 6
Star Wars V   | Star Wars 5

I could just choose to repeat the function in the cells below, as Crayon suggested, however, the range that needs to be reformatted might be 50 rows, or it might be 100 rows and I prefer not throwing in 50 extra instances of the function if they're not to be used. I want it to be as automatic as possible. :-)

I know that it's possible to retrieve the information on a range of cells, and the return that information in another range of cells just by using the following code:

function copyRange(inputRange) {
return inputRange;
}

So to input a range and output the same range isn't a problem. The problem is trying to incorporate the replace-function. I have managed to alter the information in the whole range using the 'toString()'-function. And then I was able to to split the output over several columns using 'split(",")' but I don't want it to spread across columns, just rows.

So if I somehow could convert the range/array to a string and then back to a range/array...

Is it possible to achieve this without bloating the code too much? (I'm a newbie scripter and prefer my scripts short, like my example above.)

I'm sorry if i'm being unclear. I'm used to look up answers in forums like this but not asking the questions myself!

Thanks!

EDIT: finally realized things were getting a bit too complicated so I just went with Crayons advice and used the 'dragging'-method. Saved me a lot of hazzle. Thanks for the help!!

according to https://developers.google.com/apps-script/execution_custom_functions your function can only alter data in the cell the function is invoked in, so you shouldn't be trying to change multiple cells anyways. You should have the function do the replace for that cell and then apply the function to multiple cells.

For example

A  B
i  =rom2num(A1)
i
i
i

This will make B1 equal to "1". Now hold your mouse over B1 and on the bottom-right is the dot point, drag down to B4 and you will see the function applied to rows B2-4.

edit:

In light of your comment and additional info in your question, I think I know what you're trying to do. Basically you want to exploit overflowing the value to the cells to effectively act on multiple cells. So yeah, this is possible by returning a double array. Your new example shows converting roman numerals to actual numbers ..well it's a bit more complex than simply doing a .replace but you should be able to figure out how to work that stuff into what you're trying to do, once you figure out how to get the values to work on! So here is how to do that:

function rom2num(inputRange) {
  var cells = [];
  for (var i=0;i<inputRange.length;i++) {
    cells[i] = [String(inputRange[i]).replace(/i/gi,1)];
  }
  return cells;
}

This example here iterates through each row in the range and simply replaces "i" with "1". It then returns a double array of the values, so for instance if you have

A              B
i, ii, iii     =rom2num(A1:A4)
Godfather II
iv, v, vi
Star Wars V

The function will return and overflow the cells to look like this:

A               B
i, ii, iii      1, 11, 111
Godfather II    Godfather 11
iv, v, vi       1v, v, v1
Star Wars V     Star Wars V

Like I said, you'll have to do more than just .replace (go to the link I gave you) to actually convert the roman numbers to numberals, but as far as to your actual question, this should do it.

edit 2:

I actually went ahead and incorporated the roman numeral conversion function into it because I wanted to see it. So I thought may as well share with you the final script:

function rom2num(inputRange) {
  var cells = [];
  for (var i=0;i<inputRange.length;i++) {
    cells[i] = [
      String(inputRange[i]).replace(/\b([ivxcldm]+)\b/gi,function(p,p1) {
        return deromanize(p1); 
      })
    ];
  }
  return cells;
}

function deromanize (str) {
    var str = str.toUpperCase(),
        validator = /^M*(?:D?C{0,3}|C[MD])(?:L?X{0,3}|X[CL])(?:V?I{0,3}|I[XV])$/,
        token = /[MDLV]|C[MD]?|X[CL]?|I[XV]?/g,
        key = {M:1000,CM:900,D:500,CD:400,C:100,XC:90,L:50,XL:40,X:10,IX:9,V:5,IV:4,I:1},
        num = 0, m;
    if (!(str && validator.test(str)))
        return false;
    while (m = token.exec(str))
        num += key[m[0]];
    return num;
}

Same thing as before...column A has the stuff you want to act on, put your =rom2num(A1:A4) in first cell of column B. This will put the converted roman numerals into each cell of column B, lined up with column A cells. But remember, it's not actually changing individual An > Bn cells..it's really grabbing the range you specify and overflowing the results into multiple cells. It effectively does what you want, but it's not exactly the same thing.

I used a more succinct approach:

const ss = SpreadsheetApp.getActiveSpreadsheet()
const sh = ss.getSheetByName('Sheet1')
sh
  .getRange('A:B')
  .createTextFinder('i')
  .replaceAllWith('1')

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM