Skip to content
Astera Technology

Separate subscriber digits from a phone extension

Remove declared spacing while preserving extension zeros and the raw subscriber.

Download complete case notes and answer keys ↓

Source contract and expected records

This is an original, fully synthetic mapping example. Inputs are plain, acyclic JSON-shaped records with the fields shown; the canonical shape and rejection codes belong to this example. Adapt the contract before using a different source.

This synthetic format accepts a plus prefix of one to four digits, subscriber digits with ASCII spaces, and an optional digit-string extension. Remove subscriber spaces only. Extension 007 remains text; an omitted extension becomes null. The fictional +000 prefix illustrates parsing and does not assert that a number is diallable.

Editable synthetic mapping cases
CaseInput record (JSON)Expected output (JSON)
Keep extension separate{"countryPrefix":"+000","subscriber":"1234 5678","extension":"007"}{"ok":true,"value":{"countryPrefix":"+000","subscriberDigits":"12345678","extension":"007","sourceSubscriber":"1234 5678"}}
Reject non-digit extension{"countryPrefix":"+000","subscriber":"1234","extension":"x"}{"ok":false,"error":"EXTENSION_FORMAT"}
Preserve no extension{"countryPrefix":"+000","subscriber":"1234"}{"ok":true,"value":{"countryPrefix":"+000","subscriberDigits":"1234","extension":null,"sourceSubscriber":"1234"}}
Download editable CSV ↓

Run the local transformation

Run the complete example as a JavaScript module in Node.js. It contains the pure mapping function, all three inputs and literal expected outputs; assertions stop on a mismatch. A rejected case returns ok=false with an error code, rather than a partial canonical record.

Complete function and executable cases
import assert from 'node:assert/strict';

function phoneExtension(i){
  const fail=error=>({ok:false,error});if(!i||typeof i.countryPrefix!=='string'||!/^\+\d{1,4}$/.test(i.countryPrefix)||typeof i.subscriber!=='string'||!/^[0-9 ]+$/.test(i.subscriber))return fail('PHONE_PART');
  const subscriberDigits=i.subscriber.replace(/ /g,'');if(!subscriberDigits)return fail('PHONE_PART');
  if(i.extension!==undefined&&(typeof i.extension!=='string'||!/^\d+$/.test(i.extension)))return fail('EXTENSION_FORMAT');
  return {ok:true,value:{countryPrefix:i.countryPrefix,subscriberDigits,extension:i.extension??null,sourceSubscriber:i.subscriber}};
}

// Original synthetic cases; expected outputs are literal records.
const cases = [
  {
    "label": "Keep extension separate",
    "input": {
      "countryPrefix": "+000",
      "subscriber": "1234 5678",
      "extension": "007"
    },
    "expected": {
      "ok": true,
      "value": {
        "countryPrefix": "+000",
        "subscriberDigits": "12345678",
        "extension": "007",
        "sourceSubscriber": "1234 5678"
      }
    }
  },
  {
    "label": "Reject non-digit extension",
    "input": {
      "countryPrefix": "+000",
      "subscriber": "1234",
      "extension": "x"
    },
    "expected": {
      "ok": false,
      "error": "EXTENSION_FORMAT"
    }
  },
  {
    "label": "Preserve no extension",
    "input": {
      "countryPrefix": "+000",
      "subscriber": "1234"
    },
    "expected": {
      "ok": true,
      "value": {
        "countryPrefix": "+000",
        "subscriberDigits": "1234",
        "extension": null,
        "sourceSubscriber": "1234"
      }
    }
  }
];
for (const sample of cases) {
  const actual = phoneExtension(sample.input);
  assert.deepEqual(actual, sample.expected);
  console.log(sample.label, JSON.stringify(actual));
}
Download runnable example ↓

Work through the boundary

Should 007 be appended to 12345678 or converted to 7?

Show the worked answer

Neither. subscriberDigits is "12345678" and extension is "007". The source subscriber "1234 5678" is retained separately; the extension is a distinct routing part.

Related resources