Truncate values

Thanks, rpg_digital, would this be the whole code?

const field = document.querySelector('#collocazione');
const trunc = (num, places = 0) => {
  // if places is 0 or not supplied
  // return an integer as a String
  if (places <= 0) {
    return String(Math.trunc(num.split(' ')[0]))
  }
  
  // using the RexExp constructor to dynamically create a regex
  // so places = 2 -> regex = \d+\.\d{1,2}
  const regex = new RegExp(`\\d+\\.\\d{1,${places}}`)
  const match = num.match(regex)

  return (match !== null) ? match[0] : null
}

// truncate group methods
const truncGroups = [
  {
    groupRx: /8[4-6][0-9].*/, 
    truncate: (code) => {
      // we can split a string using a regex
      // / ([A-Z]{2})/ splits code on a possible space followed by
      // 2 letters and capture those letters e.g.
      // 861.44 CU -> ['861.44', 'CU']
      // 861.44 7 -> ['861.44 7']
      const [num, letters] = code.split(/ ([A-Z]{2})/)

      // truncate number to 1 decimal place
      const truncNumber = trunc(num, 1)

      // if letters exist?
      return (letters)
        ? `${truncNumber} ${letters}` // true: return with letters
        : `${truncNumber}` // false: return without
    }
  },
  
  {
    groupRx: /80[1-7]/,
    truncate: (code) => trunc(code), // return integer
  },
  
  {
    groupRx: /839.3[16]*/,
    truncate: (code) => trunc(code, 2) // return to 2 decimal places
  }
]

const formatCode = (code) => {
  // loop through truncGroups
  for (const { groupRx, truncate } of truncGroups) {
    // test the regex against the code
    if (groupRx.test(code)) {
      return truncate(code)
    }
  }
  // didn't match so return original
  return code
}

const testCodes = [
  '847.467 4', // 847.4
  '850.767 456', // 850.7
  '869.999 3', // 869.9
  '861.39 CU', // 861.3 CU
  '863.456 CL', // 863.4 CL
  '861.444 05 AR', // 861.4 AR
  '869.347 5 BR', // 869.3 BR

  // Another group starting with 80[1-7]*
  '802.556 667567', // 802
  '805.875 4', // 805

  // Another group starting with 839.3[1,6]*
  '839.315 6', // 839.31
  '839.366 87', // 839.36
  '111.aaa'// 111.aaa
]

// check console!
testCodes.forEach((code) => console.log(code, formatCode(code)))

I cannot find my code on your saved page (link). Have you added my code to the page?

There does not seem to be any event listener associated with the ‘Collocazione’ input text edit box.

The original portal is password protected, I just saved a page. I’m using this Chrome extension to create some rules.

Ok, so I am looking at this javascript example from the Autofill extension.

So in theory using my code as an example, it would be.

const trunc = (num, places = 0) => {
  if (places <= 0) {
    return String(Math.trunc(num.split(' ')[0]))
  }

  const regex = new RegExp(`\\d+\\.\\d{1,${places}}`)
  const match = num.match(regex)

  return (match !== null) ? match[0] : null
}

const truncGroups = [
  {
    groupRx: /8[4-6][0-9].*/, 
    truncate: (code) => {
      const [num, letters] = code.split(/ ([A-Z]{2})/)
      const truncNumber = trunc(num, 1)

      return (letters)
        ? `${truncNumber} ${letters}`
        : `${truncNumber}`
    }
  },

  {
    groupRx: /80[1-7]/,
    truncate: (code) => trunc(code),
  },

  {
    groupRx: /839.3[16]*/,
    truncate: (code) => trunc(code, 2)
  }
]

const formatCode = (code) => {
  for (const { groupRx, truncate } of truncGroups) {
    if (groupRx.test(code)) {
      return truncate(code)
    }
  }
  return code
}

// Update value of <input name='collocazione'>
const collocazione = document.querySelector('#collocazione');

if (collocazione) {
  collocazione.value = formatCode(collocazione.value);
}

Thanks very much, today I can’t use the PC, I’ll let you know tomorrow… Thanks again!!

1 Like

Hi, rpg_digital, your script works well now, thanks!! Is it possible to place letters before (not after) numbers, this way?

861.39 CU > CU 861.3
863.456 CL > CL 863.4
861.444 05 AR > AR 861.4
869.347 5 BR > BR 869.3

P.S. Is it possible let Archibald’s script work as well? Thank you!

1 Like

That should be a reasonably straightforward fix, we just need to swap this around

return (letters)
  ? `${truncNumber} ${letters}`
  : `${truncNumber}`

// swap to
return (letters)
  ? `${letters} ${truncNumber}` // <- swapped around
  : `${truncNumber}`

So full script is

const truncGroups = [
  {
    groupRx: /8[4-6][0-9].*/, 
    truncate: (code) => {
      const [num, letters] = code.split(/ ([A-Z]{2})/)
      const truncNumber = trunc(num, 1)

      return (letters)
        ? `${letters} ${truncNumber}` // <- swapped around
        : `${truncNumber}`
    }
  },

  {
    groupRx: /80[1-7]/,
    truncate: (code) => trunc(code),
  },

  {
    groupRx: /839.3[16]*/,
    truncate: (code) => trunc(code, 2)
  }
]

const formatCode = (code) => {
  for (const { groupRx, truncate } of truncGroups) {
    if (groupRx.test(code)) {
      return truncate(code)
    }
  }
  return code
}

// Update value of <input name='collocazione'>
const collocazione = document.querySelector('#collocazione');

if (collocazione) {
  collocazione.value = formatCode(collocazione.value);
}

Hi, rpg_digital, the script works very well, thanks again!

1 Like

Hi, may I ask last related question?
I would like to convert these values:

823.9 (and longer numbers, for ex. 823.914 45653) > 823.9

823.[4-6] IE > 823.9 (for. ex. 823.556 3 IE > 823.9)
823.[3-4] AU > 823.9
823.[2-4] ZA > 823.9

823.[2-3] XX > 823.9
where XX could be: NZ, ET, GH, KE, NG, SO, ZW, ER, AO, MW, SL, LS
(for. ex. 823.256 3 ET > 823.9)

823.[3-4] YY > 823.9
where YY could be: IN, LK, PK, SL, SG
(for. ex. 823.347 3 LK > 823.9)

843.9 (and longer numbers for ex. 843.914 45653) > 843.9

843.[3-4] BE > 843.9 (for. ex. 843.356 3 BE > 843.9)
843.[5-6] CA > 843.9

843.[2-4] ZZ > 843.9
where ZZ could be: ML, CG, CG, CH, CI, CM, DJ, DZ, EG, GN, GP, HT, LB, MA, MG, ML, MQ, MT, MU, SN, TN, BJ, BU
(for. ex. 843.356 3 CG > 843.9)

Thanks very much!

I’m just wondering how far we are going with this? — there are a lot of numbers out there. Are there more common patterns?

When you say 823.[2-3] XX → 823.9 do you mean 823.2 XX → 823.2 or 823.3 XX → 823.3. Where is the 9 coming from?

As a start I am thinking along the lines of the following

const excludedRegions = [
  { 
    rangeRx: /823\.[2-4]/,
    excluded: [ 'ZA', 'SL' ] 
  },
  { 
    rangeRx: /823\.[2-3]/, 
    excluded: [ 'NZ', 'ET', 'GH', 'KE', 'NG', 'SO', 'ZW', 'ER', 'AO', 'MW', 'LS' ] 
  },
  { 
    rangeRx: /823\.[3-4]/, 
    excluded: [ 'AU', 'IN', 'LK', 'PK', 'SG' ] 
  },
  { 
    rangeRx: /843\.[2-4]/,
    excluded: [ 'ML', 'CG', 'CG', 'CH', 'CI', 'CM' /* ...rest here */, 'BU' ] 
  }
]

const regionExcluded = (num, region) => {
  for (const { rangeRx, excluded } of excludedRegions) {
    // does the number match the regex range and are the letters excluded
    if (rangeRx.test(String(num)) && excluded.includes(region)) {
      // is excluded
      return true
    }
  }
  // not excluded
  return false
}

const testCodes = [
  ['823.2', 'NZ'],
  ['823.3', 'KE'],
  ['823.2', 'CH'],
  ['843.3', 'CI'],
  ['843.3', 'ZW'],
]

// check console!
testCodes.forEach(
  ([num, region]) => {
    console.log(
      `${num} ${region}: ${regionExcluded(num, region) ? num : `${num} ${region}`}`, 
    )
  }
)

Output:

823.2 NZ: 823.2
823.3 KE: 823.3
823.2 CH: 823.2 CH
843.3 CI: 843.3
843.3 ZW: 843.3 ZW

Thanks, and sorry for being petulant.
The output now should never have letters and always have .9 as decimal (it’s long to explain why), as I wrote.
Examples:

823.556 3 IE > 823.9
823.358 44 AU > 823.9
823.45 ZA > 823.9

823.234 6 NZ > 823.9
823.34 KE > 823.9
823.35 ZW > 823.9 (so not 843.3 ZW > 843.3 ZW)

823.347 3 LK > 823.9

843.914 45653 > 843.9

843.356 3 BE > 843.9

843.567 6 CA > 843.9

843.246 8554 CH > 843.9 (so not 823.2 CH > 823.2 CH)
843.345 6 CI > 843.9

What should 823.112 come out as?

What if it’s GB?

See, this is important stuff.

If these are the ONLY things that can be, and you want ALL of them to resolve to 823.9 or 843.9, you dont need to do all the fancy stuff that you’ve been jumping rpg through hoops on.

if(number.substring(0,3) == "823" || number.substring(0,3) == "843") {
number = number.substring(0,3) + ".9";
}
1 Like

Thanks, m_hutley, how could I run the script on “Collocazione” field?

const collocazione = document.querySelector('#collocazione');

number = collocazione.value

Sorry, I tried, but the script is not working:

const number = document.querySelector('#collocazione').value;
if(number.substring(0,3) == "823" || number.substring(0,3) == "843") {
number = number.substring(0,3) + ".9";
}

The whole point of this is to convert dewey-decimal equivalent numbers into another format.

Here’s some test code that lets you put in some examples, and check that it gets properly converted…

const tests = [
    {code: "861.39 CU", expected: "CU 861.3"},
    {code: "863.456 CL", expected: "CL 863.4"},
    {code: "861.444 05 AR", expected: "AR 861.4"},
    {code: "869.347 5 BR", expected: "BR 869.3"}
];

function convertBookCode(bookCode) {
  const author = bookCode.match(/[A-Z]{2}/)[0];
  const code = Number(bookCode.match(/\d+\.\d+/)[0]);
  const rounded = Math.floor(code * 10) / 10;
  return `${author} ${rounded}`;
}

tests.forEach(function ({code, expected}) {
  const converted = convertBookCode(code);
  const success = (converted === expected ? 'Pass' : 'Fail');
  const result = document.querySelector("#result");
  result.innerHTML += `<p>${code} => ${expected} ${success}</p>`;
});

The code can be found at https://jsfiddle.net/eophsj0r/1/

It looks like the requirements are changing we go. A consistent set of tests to help nail down the requirements, helps to avoid confusion.

With the updated set of restrictions from post #37 where the two-letters aren’t output and you just have the integer digits always ending with .9, we have the following updated code:

const tests = [
    {code: "823.556 3 IE", expected: "823.9"},
    {code: "823.358 44 AU", expected: "823.9"},
    {code: "823.45 ZA", expected: "823.9"},
    {code: "823.234 6 NZ", expected: "823.9"},
    {code: "823.34 KE", expected: "823.9"},
    {code: "823.35 ZW", expected: "823.9"},
    {code: "823.347 3 LK", expected: "823.9"},
    {code: "843.914 45653", expected: "843.9"},
    {code: "843.356 3 BE", expected: "843.9"},
    {code: "843.567 6 CA", expected: "843.9"},
    {code: "843.246 8554 CH", expected: "843.9"},
    {code: "843.345 6 CI", expected: "843.9"},
];

function convertBookCode(bookCode) {
  const code = Number(bookCode.match(/\d+/)[0]);
  return `${code}.9`;
}

tests.forEach(function ({code, expected}) {
  const converted = convertBookCode(code);
  const success = (converted === expected ? 'Pass' : 'Fail');
  const result = document.querySelector("#result");
  result.innerHTML += `<p>${code} => ${expected} ${success}</p>`;
});

The above code is found at https://jsfiddle.net/14Letaro/

That function can even be simplified if it doesn’t need to cope with other more complex situations.

function convertBookCode(bookCode) {
  return bookCode.substring(0, 3) + ".9";
}

Thanks, Paul_Wilkins, could you tell me how could I adapt your three scripts to run on “#Collocazione” field, using Chrome’s Autofill extension?
I tried replacing “result” with “collocazione” but didn’t work:

[…]

tests.forEach(function ({code, expected}) {
  const converted = convertBookCode(code);
  const success = (converted === expected ? 'Pass' : 'Fail');
  const collocazione = document.querySelector("#collocazione");
  collocazione.innerHTML += `<p>${code} => ${expected} ${success}</p>`;
});

Let’s start from the most recent working code that you have, as was announced in post #34