-
-
Notifications
You must be signed in to change notification settings - Fork 665
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(formula): supplement text formulas (#3842)
Co-authored-by: wpxp123456 <Wpxp1223456>
- Loading branch information
1 parent
6142b07
commit 114f6dc
Showing
47 changed files
with
3,535 additions
and
716 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
143 changes: 143 additions & 0 deletions
143
packages/engine-formula/src/functions/text/find/__test__/index.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
/** | ||
* Copyright 2023-present DreamNum Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
import { describe, expect, it } from 'vitest'; | ||
|
||
import { ErrorType } from '../../../../basics/error-type'; | ||
import { ArrayValueObject, transformToValueObject } from '../../../../engine/value-object/array-value-object'; | ||
import { ErrorValueObject } from '../../../../engine/value-object/base-value-object'; | ||
import { BooleanValueObject, NullValueObject, NumberValueObject, StringValueObject } from '../../../../engine/value-object/primitive-object'; | ||
import { getObjectValue } from '../../../__tests__/create-function-test-bed'; | ||
import { FUNCTION_NAMES_TEXT } from '../../function-names'; | ||
import { Find } from '../index'; | ||
|
||
describe('Test find function', () => { | ||
const testFunction = new Find(FUNCTION_NAMES_TEXT.FIND); | ||
|
||
describe('Find', () => { | ||
it('Value is normal', () => { | ||
const findText = StringValueObject.create('Univer'); | ||
const withinText = StringValueObject.create('Hello Univer'); | ||
const startNum = NumberValueObject.create(1); | ||
const result = testFunction.calculate(findText, withinText, startNum); | ||
expect(getObjectValue(result)).toStrictEqual(7); | ||
}); | ||
|
||
it('FindText value test', () => { | ||
const findText = NullValueObject.create(); | ||
const withinText = StringValueObject.create('Hello Univer'); | ||
const startNum = NumberValueObject.create(1); | ||
const result = testFunction.calculate(findText, withinText, startNum); | ||
expect(getObjectValue(result)).toStrictEqual(1); | ||
|
||
const findText2 = BooleanValueObject.create(false); | ||
const result2 = testFunction.calculate(findText2, withinText, startNum); | ||
expect(getObjectValue(result2)).toStrictEqual(ErrorType.VALUE); | ||
|
||
const findText3 = StringValueObject.create('test'); | ||
const result3 = testFunction.calculate(findText3, withinText, startNum); | ||
expect(getObjectValue(result3)).toStrictEqual(ErrorType.VALUE); | ||
|
||
const findText4 = ErrorValueObject.create(ErrorType.NAME); | ||
const result4 = testFunction.calculate(findText4, withinText, startNum); | ||
expect(getObjectValue(result4)).toStrictEqual(ErrorType.NAME); | ||
}); | ||
|
||
it('WithinText value test', () => { | ||
const findText = StringValueObject.create('Univer'); | ||
const withinText = NullValueObject.create(); | ||
const startNum = NumberValueObject.create(1); | ||
const result = testFunction.calculate(findText, withinText, startNum); | ||
expect(getObjectValue(result)).toStrictEqual(ErrorType.VALUE); | ||
|
||
const withinText2 = BooleanValueObject.create(false); | ||
const result2 = testFunction.calculate(findText, withinText2, startNum); | ||
expect(getObjectValue(result2)).toStrictEqual(ErrorType.VALUE); | ||
|
||
const withinText3 = StringValueObject.create('test'); | ||
const result3 = testFunction.calculate(findText, withinText3, startNum); | ||
expect(getObjectValue(result3)).toStrictEqual(ErrorType.VALUE); | ||
|
||
const withinText4 = ErrorValueObject.create(ErrorType.NAME); | ||
const result4 = testFunction.calculate(findText, withinText4, startNum); | ||
expect(getObjectValue(result4)).toStrictEqual(ErrorType.NAME); | ||
}); | ||
|
||
it('StartNum value test', () => { | ||
const findText = StringValueObject.create('Univer'); | ||
const withinText = StringValueObject.create('Hello Univer'); | ||
const startNum = NullValueObject.create(); | ||
const result = testFunction.calculate(findText, withinText, startNum); | ||
expect(getObjectValue(result)).toStrictEqual(ErrorType.VALUE); | ||
|
||
const startNum2 = BooleanValueObject.create(true); | ||
const result2 = testFunction.calculate(findText, withinText, startNum2); | ||
expect(getObjectValue(result2)).toStrictEqual(7); | ||
|
||
const startNum3 = StringValueObject.create('test'); | ||
const result3 = testFunction.calculate(findText, withinText, startNum3); | ||
expect(getObjectValue(result3)).toStrictEqual(ErrorType.VALUE); | ||
|
||
const startNum4 = ErrorValueObject.create(ErrorType.NAME); | ||
const result4 = testFunction.calculate(findText, withinText, startNum4); | ||
expect(getObjectValue(result4)).toStrictEqual(ErrorType.NAME); | ||
|
||
const startNum5 = NumberValueObject.create(13); | ||
const result5 = testFunction.calculate(findText, withinText, startNum5); | ||
expect(getObjectValue(result5)).toStrictEqual(ErrorType.VALUE); | ||
}); | ||
|
||
it('Value is array', () => { | ||
const findText = ArrayValueObject.create({ | ||
calculateValueList: transformToValueObject([ | ||
[1, ' ', '中文测试', true, false, null], | ||
[0, 'm', '2.34', 'M', -3, ErrorType.NAME], | ||
]), | ||
rowCount: 2, | ||
columnCount: 6, | ||
unitId: '', | ||
sheetId: '', | ||
row: 0, | ||
column: 0, | ||
}); | ||
const withinText = StringValueObject.create('Miriam McGovern'); | ||
const startNum = NumberValueObject.create(2); | ||
const result = testFunction.calculate(findText, withinText, startNum); | ||
expect(getObjectValue(result)).toStrictEqual([ | ||
[ErrorType.VALUE, 7, ErrorType.VALUE, ErrorType.VALUE, ErrorType.VALUE, 2], | ||
[ErrorType.VALUE, 6, ErrorType.VALUE, 8, ErrorType.VALUE, ErrorType.NAME], | ||
]); | ||
}); | ||
|
||
it('More test', () => { | ||
const findText = StringValueObject.create('o'); | ||
const withinText = StringValueObject.create('Hello中文o😊Wo😊rld'); | ||
const startNum = ArrayValueObject.create('{1,6,9,13}'); | ||
const result = testFunction.calculate(findText, withinText, startNum); | ||
expect(getObjectValue(result)).toStrictEqual([ | ||
[5, 8, 12, ErrorType.VALUE], | ||
]); | ||
|
||
const findText2 = StringValueObject.create('2'); | ||
const withinText2 = StringValueObject.create('2012-2-2'); | ||
const startNum2 = ArrayValueObject.create('{1,2,5,7}'); | ||
const result2 = testFunction.calculate(findText2, withinText2, startNum2); | ||
expect(getObjectValue(result2)).toStrictEqual([ | ||
[1, 4, 6, 8], | ||
]); | ||
}); | ||
}); | ||
}); |
106 changes: 106 additions & 0 deletions
106
packages/engine-formula/src/functions/text/find/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
/** | ||
* Copyright 2023-present DreamNum Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
import type { ArrayValueObject } from '../../../engine/value-object/array-value-object'; | ||
import { ErrorType } from '../../../basics/error-type'; | ||
import { getTextValueOfNumberFormat } from '../../../basics/format'; | ||
import { expandArrayValueObject } from '../../../engine/utils/array-object'; | ||
import { checkVariantsErrorIsStringToNumber } from '../../../engine/utils/check-variant-error'; | ||
import { type BaseValueObject, ErrorValueObject } from '../../../engine/value-object/base-value-object'; | ||
import { NumberValueObject } from '../../../engine/value-object/primitive-object'; | ||
import { BaseFunction } from '../../base-function'; | ||
|
||
export class Find extends BaseFunction { | ||
override minParams = 2; | ||
|
||
override maxParams = 3; | ||
|
||
override calculate(findText: BaseValueObject, withinText: BaseValueObject, startNum?: BaseValueObject): BaseValueObject { | ||
const _startNum = startNum ?? NumberValueObject.create(1); | ||
|
||
const maxRowLength = Math.max( | ||
findText.isArray() ? (findText as ArrayValueObject).getRowCount() : 1, | ||
withinText.isArray() ? (withinText as ArrayValueObject).getRowCount() : 1, | ||
_startNum.isArray() ? (_startNum as ArrayValueObject).getRowCount() : 1 | ||
); | ||
|
||
const maxColumnLength = Math.max( | ||
findText.isArray() ? (findText as ArrayValueObject).getColumnCount() : 1, | ||
withinText.isArray() ? (withinText as ArrayValueObject).getColumnCount() : 1, | ||
_startNum.isArray() ? (_startNum as ArrayValueObject).getColumnCount() : 1 | ||
); | ||
|
||
const findTextArray = expandArrayValueObject(maxRowLength, maxColumnLength, findText, ErrorValueObject.create(ErrorType.NA)); | ||
const withinTextArray = expandArrayValueObject(maxRowLength, maxColumnLength, withinText, ErrorValueObject.create(ErrorType.NA)); | ||
const startNumArray = expandArrayValueObject(maxRowLength, maxColumnLength, _startNum, ErrorValueObject.create(ErrorType.NA)); | ||
|
||
const resultArray = findTextArray.mapValue((findTextObject, rowIndex, columnIndex) => { | ||
const withinTextObject = withinTextArray.get(rowIndex, columnIndex) as BaseValueObject; | ||
const startNumObject = startNumArray.get(rowIndex, columnIndex) as BaseValueObject; | ||
|
||
if (findTextObject.isError()) { | ||
return findTextObject; | ||
} | ||
|
||
if (withinTextObject.isError()) { | ||
return withinTextObject; | ||
} | ||
|
||
if (startNumObject.isError()) { | ||
return startNumObject; | ||
} | ||
|
||
return this._handleSingleObject(findTextObject, withinTextObject, startNumObject); | ||
}); | ||
|
||
if (maxRowLength === 1 && maxColumnLength === 1) { | ||
return (resultArray as ArrayValueObject).get(0, 0) as BaseValueObject; | ||
} | ||
|
||
return resultArray; | ||
} | ||
|
||
private _handleSingleObject(findText: BaseValueObject, withinText: BaseValueObject, startNum: BaseValueObject): BaseValueObject { | ||
const findTextValue = getTextValueOfNumberFormat(findText); | ||
const withinTextValue = getTextValueOfNumberFormat(withinText); | ||
|
||
const { isError, errorObject, variants } = checkVariantsErrorIsStringToNumber(startNum); | ||
|
||
if (isError) { | ||
return errorObject as BaseValueObject; | ||
} | ||
|
||
const [startNumObject] = variants as BaseValueObject[]; | ||
|
||
const startNumValue = Math.floor(+startNumObject.getValue()); | ||
|
||
if (withinText.isNull() || startNumValue <= 0 || startNumValue > withinTextValue.length) { | ||
return ErrorValueObject.create(ErrorType.VALUE); | ||
} | ||
|
||
if (findText.isNull() || findTextValue.length === 0) { | ||
return NumberValueObject.create(startNumValue); | ||
} | ||
|
||
const result = withinTextValue.indexOf(findTextValue, startNumValue - 1); | ||
|
||
if (result === -1) { | ||
return ErrorValueObject.create(ErrorType.VALUE); | ||
} | ||
|
||
return NumberValueObject.create(result + 1); | ||
} | ||
} |
Oops, something went wrong.