stdlib icon indicating copy to clipboard operation
stdlib copied to clipboard

[RFC]: add `@stdlib/assert/is-complex-string`

Open marsian83 opened this issue 1 year ago • 14 comments

Description

This RFC proposes adding package @stdlib/assert/is-complex-string.

The package should be similar in structure to @stdlib/complex/reviver-float32.

The goal is to assert if an input string is of a complex number format string(a + ib) or (a+bi) where, a and b are numbers

 function isComplexString( str ) => boolean

Eg : isComplexString( "32+12i" ) returns true Eg : isComplexString( "32+i12" ) returns true Eg : isComplexString( null ) returns true Eg : isComplexString( "" ) returns false Eg : isComplexString( "abcd+12i" ) returns false Eg : isComplexString( Infinity ) returns false

Package: @stdlib/assert/is-complex-string Alias: isComplexString

Related Issues

Can help with issues #1332 and #1333

Questions

This is my first issue so I'd like to know if the way I have proposed the feature is correct

Other

No response

Checklist

  • [X] I have read and understood the Code of Conduct.
  • [X] Searched for existing issues and pull requests.
  • [X] The issue name begins with RFC:.

marsian83 avatar Feb 24 '24 12:02 marsian83

:wave: Hi there! :wave:

And thank you for opening your first issue! We will get back to you shortly. :runner: :dash:

stdlib-bot avatar Feb 24 '24 12:02 stdlib-bot

I would like to implement this myself. as a supporting assertion to #1332

marsian83 avatar Feb 24 '24 12:02 marsian83

ok, so I took the initiative to start implementing this and I figured there would be 2 ways to approach this

one, using a regex

/^[-+]?\d*\.?\d+(?:[eE][-+]?\d+)?[-+]\d*\.?\d*(?:[eE][-+]?\d+)?i$/

This regex is quite popular as I have seen it everywhere on the internet while trying to look for a regex

secondly, I could implement a function to manually parse the string something like this


function isComplexString( str ) {
	if ( !isString( str ) ) {
		return false;
	}
	
    let re = '';
    let im = '';
    let hasIota = false;
    let i = 0;

    while (str[i] === ' ') {
        i++;
    }

    while (i < str.length && (str[i] >= '0' && str[i] <= '9' || str[i] === '.'
			|| str[i] === '+' || str[i] === '-')) {
        if (str[i] === 'i') {
            return false; // 'i' must not be in the real part
        }
        re += str[i++];
    }

    if (re.length === 0) {
        return false; // No real part
    }

    if (str[i] === '+' || str[i] === '-') {
        im += str[i++];
    }

    while (i < str.length && (str[i] >= '0' && str[i] <= '9' || str[i] === '.'
			|| str[i] === 'i')) {
        if (str[i] === 'i') {
            if (hasIota) {
                return false; // Duplicate 'i'
            }
            hasIota = true;
        }
        im += str[i++];
    }

    if (!hasIota) {
        return false; // No 'i' in the imaginary part
    }

    while (i < str.length) {
        if (str[i++] !== ' ') {
            return false; // non whitespace character after end of the string
        }
    }

    return true;
}


marsian83 avatar Feb 24 '24 14:02 marsian83

which one of these approaches would be preferable according to the standards of other implementations in the codebas? @Planeshifter @kgryte

marsian83 avatar Feb 24 '24 14:02 marsian83

You're right to identify that we need to handle exponential notation (see your regex).

1 + 2i
1
2i
-2i
2i
1.523 - 4.234i
-1.5 + 4.2i
1.0e10 -2.0e-10i
1.0E10 + 4.1e+10i
1+2i
1-0i
0+1i
-0.0 + 2.0i
NaN + NaNi
Infinity-Infinityi

These should all be valid. Notice that we should also handle NaNs and infinities.

kgryte avatar Feb 24 '24 22:02 kgryte

My initial sense is that I suggest implementing a manual tokenizer/parser, as a regexp is more likely to be fiddly and given the variety of values, signs, etc, likely to become inscrutable.

kgryte avatar Feb 24 '24 22:02 kgryte

@marsian83 Perhaps before actually implementing this function and inlining the implementation, you should propose implementing @stdlib/complex/base/parse-string, which implements the tokenizer/parser and, if the string is valid, returns a complex-like object (e.g., { 're': 3.0, 'im': 5.0 }) or, if the string is not valid, returns null.

Then in this package, the implementation is simply

function isComplexString( value ) {
	return (
		isString( value ) &&
		parse( value ) !== null
	);
}

kgryte avatar Feb 24 '24 22:02 kgryte

@marsian83 Perhaps before actually implementing this function and inlining the implementation, you should propose implementing @stdlib/complex/base/parse-string, which implements the tokenizer/parser and, if the string is valid, returns a complex-like object (e.g., { 're': 3.0, 'im': 5.0 }) or, if the string is not valid, returns null.

Then in this package, the implementation is simply

function isComplexString( value ) {
	return (
		isString( value ) &&
		parse( value ) !== null
	);
}

Hi @kgryte , I have implemented the parse function but when trying to lint I have been facing this issue since my first issue

please Can you help me resolve this image

marsian83 avatar Feb 25 '24 12:02 marsian83

Hey there! Can you assign me this issue?

Codesmith28 avatar Feb 25 '24 13:02 Codesmith28

@marsian83 Please run make init, which will initialize the missing ESLint plugin.

Planeshifter avatar Feb 25 '24 14:02 Planeshifter

@marsian83 Please run make init, which will initialize the missing ESLint plugin.

image

Hi, now I am just getting different errors

marsian83 avatar Feb 25 '24 14:02 marsian83

@marsian83 Please run make init, which will initialize the missing ESLint plugin.

image Hi, now I am just getting different errors

I was getting these too. Try running make install-node-modules (after restoring the package.json that you might have lost). In my case, I was running it on WSL and setting up was really slow. If you're on windows, I suggest spinning up a Github Codespace instead of developing locally, it takes like 2 minutes to set up with no problems or errors.

Snehil-Shah avatar Feb 25 '24 14:02 Snehil-Shah

@marsian83 Perhaps before actually implementing this function and inlining the implementation, you should propose implementing @stdlib/complex/base/parse-string, which implements the tokenizer/parser and, if the string is valid, returns a complex-like object (e.g., { 're': 3.0, 'im': 5.0 }) or, if the string is not valid, returns null.

Then in this package, the implementation is simply

function isComplexString( value ) {
	return (
		isString( value ) &&
		parse( value ) !== null
	);
}

Hi @kgryte , I have made a PR with a possible implementation for this.

marsian83 avatar Feb 25 '24 16:02 marsian83

Now that the @stdlib/complex/base/parse has been implemented This can now be implemented as well. I will get to working on this.

marsian83 avatar Feb 26 '24 15:02 marsian83