fix(integer-basee-converter): handle prefix/suffix and case in sensitive
Handle common languages prefix : 0x, 0o, 0b (C/C#), &H, &O, &B (vb.net) Handle common languages suffix : I (vb.net), U/L (C/C# unsigned and long), n (js bigint) Handle case insensitive for base < 36 (ie, hexa) ( 36 = décimal + lower letters) Fix #694
This commit is contained in:
		
							parent
							
								
									a07806cd15
								
							
						
					
					
						commit
						e336ebe6bb
					
				@ -11,6 +11,21 @@ describe('integer-base-converter', () => {
 | 
				
			|||||||
        expect(convertBase({ value: '10100101', fromBase: 2, toBase: 16 })).toEqual('a5');
 | 
					        expect(convertBase({ value: '10100101', fromBase: 2, toBase: 16 })).toEqual('a5');
 | 
				
			||||||
        expect(convertBase({ value: '192654', fromBase: 10, toBase: 8 })).toEqual('570216');
 | 
					        expect(convertBase({ value: '192654', fromBase: 10, toBase: 8 })).toEqual('570216');
 | 
				
			||||||
        expect(convertBase({ value: 'zz', fromBase: 64, toBase: 10 })).toEqual('2275');
 | 
					        expect(convertBase({ value: 'zz', fromBase: 64, toBase: 10 })).toEqual('2275');
 | 
				
			||||||
 | 
					        expect(convertBase({ value: 'AA', fromBase: 16, toBase: 10 })).toEqual('170');
 | 
				
			||||||
 | 
					        expect(convertBase({ value: 'aa', fromBase: 16, toBase: 10 })).toEqual('170');
 | 
				
			||||||
 | 
					        expect(convertBase({ value: '0xAA', fromBase: -1, toBase: 10 })).toEqual('170');
 | 
				
			||||||
 | 
					        expect(convertBase({ value: '&HAA', fromBase: -1, toBase: 10 })).toEqual('170');
 | 
				
			||||||
 | 
					        expect(convertBase({ value: '0xAAUL', fromBase: -1, toBase: 10 })).toEqual('170');
 | 
				
			||||||
 | 
					        expect(convertBase({ value: '0XAAUL', fromBase: -1, toBase: 10 })).toEqual('170');
 | 
				
			||||||
 | 
					        expect(convertBase({ value: '10UL', fromBase: 10, toBase: 10 })).toEqual('10');
 | 
				
			||||||
 | 
					        expect(convertBase({ value: '10n', fromBase: 10, toBase: 10 })).toEqual('10');
 | 
				
			||||||
 | 
					        expect(convertBase({ value: '0o252', fromBase: -1, toBase: 10 })).toEqual('170');
 | 
				
			||||||
 | 
					        expect(convertBase({ value: '&O252', fromBase: -1, toBase: 10 })).toEqual('170');
 | 
				
			||||||
 | 
					        expect(convertBase({ value: '192 654', fromBase: 10, toBase: 8 })).toEqual('570216');
 | 
				
			||||||
 | 
					        expect(convertBase({ value: '192.654', fromBase: 10, toBase: 8 })).toEqual('570216');
 | 
				
			||||||
 | 
					        expect(convertBase({ value: '0b10101010', fromBase: -1, toBase: 10 })).toEqual('170');
 | 
				
			||||||
 | 
					        expect(convertBase({ value: '0b_1010_1010', fromBase: -1, toBase: 10 })).toEqual('170');
 | 
				
			||||||
 | 
					        expect(convertBase({ value: '192,654', fromBase: 10, toBase: 8 })).toEqual('570216');
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
				
			|||||||
@ -1,15 +1,56 @@
 | 
				
			|||||||
export function convertBase({ value, fromBase, toBase }: { value: string; fromBase: number; toBase: number }) {
 | 
					export function hasNumberPrefix(value: string) {
 | 
				
			||||||
 | 
					  return (value ?? '').trim().match(/^(0[xob].|&[hob].)/i);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function convertBase(
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    value, fromBase, toBase,
 | 
				
			||||||
 | 
					    ignorePunctuationsRegexChars = ' \u00A0_\.,-',
 | 
				
			||||||
 | 
					    handlePrefixSuffix = true,
 | 
				
			||||||
 | 
					    ignoreCase = true,
 | 
				
			||||||
 | 
					  }: {
 | 
				
			||||||
 | 
					    value: string
 | 
				
			||||||
 | 
					    fromBase: number
 | 
				
			||||||
 | 
					    toBase: number
 | 
				
			||||||
 | 
					    ignorePunctuationsRegexChars?: string
 | 
				
			||||||
 | 
					    handlePrefixSuffix?: boolean
 | 
				
			||||||
 | 
					    ignoreCase?: boolean
 | 
				
			||||||
 | 
					  }) {
 | 
				
			||||||
 | 
					  let cleanedValue = (value ?? '0').trim();
 | 
				
			||||||
 | 
					  if (ignorePunctuationsRegexChars) {
 | 
				
			||||||
 | 
					    cleanedValue = cleanedValue.replace(new RegExp(`[${ignorePunctuationsRegexChars}]`, 'g'), '');
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  let finalFromBase = fromBase;
 | 
				
			||||||
 | 
					  if (handlePrefixSuffix) {
 | 
				
			||||||
 | 
					    for (const regBase of [
 | 
				
			||||||
 | 
					      { base: 2, regex: /^(&b|0b)?([01]+)([IULZn]*)$/i },
 | 
				
			||||||
 | 
					      { base: 8, regex: /^(&o|0o)?([0-7]+)([IULZn]*)$/i },
 | 
				
			||||||
 | 
					      { base: 16, regex: /^(&h|0x)?([a-f0-9]+)([IULZn]*)$/i },
 | 
				
			||||||
 | 
					    ]) {
 | 
				
			||||||
 | 
					      const match = cleanedValue.match(regBase.regex);
 | 
				
			||||||
 | 
					      if (match) {
 | 
				
			||||||
 | 
					        if (match[1]) {
 | 
				
			||||||
 | 
					          finalFromBase = regBase.base;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        cleanedValue = match[2];
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (ignoreCase && finalFromBase <= 36) {
 | 
				
			||||||
 | 
					    cleanedValue = cleanedValue.toLowerCase();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  const range = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/'.split('');
 | 
					  const range = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/'.split('');
 | 
				
			||||||
  const fromRange = range.slice(0, fromBase);
 | 
					  const fromRange = range.slice(0, finalFromBase);
 | 
				
			||||||
  const toRange = range.slice(0, toBase);
 | 
					  const toRange = range.slice(0, toBase);
 | 
				
			||||||
  let decValue = value
 | 
					  let decValue = cleanedValue
 | 
				
			||||||
    .split('')
 | 
					    .split('')
 | 
				
			||||||
    .reverse()
 | 
					    .reverse()
 | 
				
			||||||
    .reduce((carry: number, digit: string, index: number) => {
 | 
					    .reduce((carry: number, digit: string, index: number) => {
 | 
				
			||||||
      if (!fromRange.includes(digit)) {
 | 
					      if (!fromRange.includes(digit)) {
 | 
				
			||||||
        throw new Error(`Invalid digit "${digit}" for base ${fromBase}.`);
 | 
					        throw new Error(`Invalid digit "${digit}" for base ${finalFromBase}.`);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      return (carry += fromRange.indexOf(digit) * fromBase ** index);
 | 
					      return (carry += fromRange.indexOf(digit) * finalFromBase ** index);
 | 
				
			||||||
    }, 0);
 | 
					    }, 0);
 | 
				
			||||||
  let newValue = '';
 | 
					  let newValue = '';
 | 
				
			||||||
  while (decValue > 0) {
 | 
					  while (decValue > 0) {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import InputCopyable from '../../components/InputCopyable.vue';
 | 
					import InputCopyable from '../../components/InputCopyable.vue';
 | 
				
			||||||
import { convertBase } from './integer-base-converter.model';
 | 
					import { convertBase, hasNumberPrefix } from './integer-base-converter.model';
 | 
				
			||||||
import { getErrorMessageIfThrows } from '@/utils/error';
 | 
					import { getErrorMessageIfThrows } from '@/utils/error';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const inputProps = {
 | 
					const inputProps = {
 | 
				
			||||||
@ -15,6 +15,8 @@ const input = ref('42');
 | 
				
			|||||||
const inputBase = ref(10);
 | 
					const inputBase = ref(10);
 | 
				
			||||||
const outputBase = ref(42);
 | 
					const outputBase = ref(42);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const hasInputNumberPrefix = computed(() => hasNumberPrefix(input.value));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function errorlessConvert(...args: Parameters<typeof convertBase>) {
 | 
					function errorlessConvert(...args: Parameters<typeof convertBase>) {
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
    return convertBase(...args);
 | 
					    return convertBase(...args);
 | 
				
			||||||
@ -36,7 +38,7 @@ const error = computed(() =>
 | 
				
			|||||||
    <c-card>
 | 
					    <c-card>
 | 
				
			||||||
      <c-input-text v-model:value="input" label="Input number" placeholder="Put your number here (ex: 42)" label-position="left" label-width="110px" mb-2 label-align="right" />
 | 
					      <c-input-text v-model:value="input" label="Input number" placeholder="Put your number here (ex: 42)" label-position="left" label-width="110px" mb-2 label-align="right" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <n-form-item label="Input base" label-placement="left" label-width="110" :show-feedback="false">
 | 
					      <n-form-item v-if="!hasInputNumberPrefix" label="Input base" label-placement="left" label-width="110" :show-feedback="false">
 | 
				
			||||||
        <n-input-number v-model:value="inputBase" max="64" min="2" placeholder="Put your input base here (ex: 10)" w-full />
 | 
					        <n-input-number v-model:value="inputBase" max="64" min="2" placeholder="Put your input base here (ex: 10)" w-full />
 | 
				
			||||||
      </n-form-item>
 | 
					      </n-form-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user