Fix regexp filtering errors

This commit is contained in:
IRBorisov 2023-10-04 18:46:52 +03:00
parent ce513eeb90
commit 09c95cb81f
8 changed files with 52 additions and 21 deletions

View File

@ -1,5 +1,7 @@
// Module: Schema library models. // Module: Schema library models.
import { TextMatcher } from '../utils/utils'
// ========= Users =========== // ========= Users ===========
export interface IUser { export interface IUser {
id: number | null id: number | null
@ -53,13 +55,7 @@ export interface ILibraryUpdateData
// ============= API =============== // ============= API ===============
export function matchLibraryItem(query: string, target: ILibraryItem): boolean { export function matchLibraryItem(query: string, target: ILibraryItem): boolean {
const queryI = query.toUpperCase() const matcher = new TextMatcher(query);
if (target.alias.toUpperCase().match(queryI)) { return matcher.test(target.alias) || matcher.test(target.title);
return true
} else if (target.title.toUpperCase().match(queryI)) {
return true
} else {
return false
}
} }

View File

@ -1,4 +1,5 @@
import { Graph } from '../utils/Graph' import { Graph } from '../utils/Graph'
import { TextMatcher } from '../utils/utils'
import { ILibraryUpdateData } from './library' import { ILibraryUpdateData } from './library'
import { ILibraryItem } from './library' import { ILibraryItem } from './library'
import { CstMatchMode } from './miscelanious' import { CstMatchMode } from './miscelanious'
@ -215,21 +216,22 @@ export function loadRSFormData(schema: IRSFormData): IRSForm {
return result; return result;
} }
export function matchConstituenta(query: string, target: IConstituenta, mode: CstMatchMode) { export function matchConstituenta(query: string, target: IConstituenta, mode: CstMatchMode): boolean {
const matcher = new TextMatcher(query);
if ((mode === CstMatchMode.ALL || mode === CstMatchMode.NAME) && if ((mode === CstMatchMode.ALL || mode === CstMatchMode.NAME) &&
target.alias.match(query)) { matcher.test(target.alias)) {
return true; return true;
} }
if ((mode === CstMatchMode.ALL || mode === CstMatchMode.TERM) && if ((mode === CstMatchMode.ALL || mode === CstMatchMode.TERM) &&
target.term_resolved.match(query)) { matcher.test(target.term_resolved)) {
return true; return true;
} }
if ((mode === CstMatchMode.ALL || mode === CstMatchMode.EXPR) && if ((mode === CstMatchMode.ALL || mode === CstMatchMode.EXPR) &&
target.definition_formal.match(query)) { matcher.test(target.definition_formal)) {
return true; return true;
} }
if ((mode === CstMatchMode.ALL || mode === CstMatchMode.TEXT)) { if ((mode === CstMatchMode.ALL || mode === CstMatchMode.TEXT)) {
return (target.definition_resolved.match(query) || target.convention.match(query)); return (matcher.test(target.definition_resolved) || matcher.test(target.convention));
} }
return false; return false;
} }

View File

@ -166,6 +166,7 @@ export enum TokenID {
} }
export enum RSErrorType { export enum RSErrorType {
unknownSymbol = 33283,
syntax = 33792, syntax = 33792,
missingParanthesis = 33798, missingParanthesis = 33798,
missingCurlyBrace = 33799, missingCurlyBrace = 33799,

View File

@ -74,6 +74,7 @@ function DlgCreateCst({ hideWindow, initial, onCreate }: DlgCreateCstProps) {
onChange={event => setTerm(event.target.value)} onChange={event => setTerm(event.target.value)}
/> />
<RSInput id='expression' label='Формальное выражение' <RSInput id='expression' label='Формальное выражение'
placeholder='Родоструктурное выражение, задающее формальное определение'
editable editable
height='5.5rem' height='5.5rem'
value={expression} value={expression}

View File

@ -240,7 +240,7 @@ function DlgEditWordForms({ hideWindow, target, onSave }: DlgEditWordFormsProps)
spellCheck spellCheck
/> />
<div className='text-sm mt-4 mb-2 font-semibold'> <div className='mt-4 mb-2 text-sm font-semibold'>
Параметры словоформы Параметры словоформы
</div> </div>
@ -283,7 +283,7 @@ function DlgEditWordForms({ hideWindow, target, onSave }: DlgEditWordFormsProps)
/> />
</div> </div>
<div className='flex flex-start justify-between'> <div className='flex justify-between flex-start'>
<div className='flex items-center justify-start'> <div className='flex items-center justify-start'>
<MiniButton <MiniButton
tooltip='Внести словоформу' tooltip='Внести словоформу'
@ -304,7 +304,7 @@ function DlgEditWordForms({ hideWindow, target, onSave }: DlgEditWordFormsProps)
onClick={handleGenerateLexeme} onClick={handleGenerateLexeme}
/> />
</div> </div>
<div className='text-sm mt-2 mb-1 font-semibold w-full text-center'> <div className='w-full mt-2 mb-1 text-sm font-semibold text-center'>
Заданные вручную словоформы: [{forms.length}] Заданные вручную словоформы: [{forms.length}]
</div> </div>
<MiniButton <MiniButton

View File

@ -92,6 +92,7 @@ function ViewSideConstituents({ expression, baseHeight, activeID, onOpenEdit }:
filtered = applyGraphFilter(schema, activeID, filterSource); filtered = applyGraphFilter(schema, activeID, filterSource);
} }
if (filterText) { if (filterText) {
console.log(filterText);
filtered = filtered.filter((cst) => matchConstituenta(filterText, cst, filterMatch)); filtered = filtered.filter((cst) => matchConstituenta(filterText, cst, filterMatch));
} }
setFilteredData(filtered); setFilteredData(filtered);
@ -141,9 +142,9 @@ function ViewSideConstituents({ expression, baseHeight, activeID, onOpenEdit }:
columnHelper.accessor(cst => describeConstituenta(cst), { columnHelper.accessor(cst => describeConstituenta(cst), {
id: 'description', id: 'description',
header: 'Описание', header: 'Описание',
size: 500, size: 1000,
minSize: 350, minSize: 350,
maxSize: 500, maxSize: 1000,
cell: props => cell: props =>
<div style={{ <div style={{
fontSize: 12, fontSize: 12,
@ -155,9 +156,9 @@ function ViewSideConstituents({ expression, baseHeight, activeID, onOpenEdit }:
columnHelper.accessor('definition_formal', { columnHelper.accessor('definition_formal', {
id: 'expression', id: 'expression',
header: 'Выражение', header: 'Выражение',
size: 1000, size: 2000,
minSize: 0, minSize: 0,
maxSize: 1000, maxSize: 2000,
enableHiding: true, enableHiding: true,
cell: props => cell: props =>
<div style={{ <div style={{

View File

@ -438,6 +438,8 @@ export function labelGrammeme(gram: GramData): string {
export function describeRSError(error: IRSErrorDescription): string { export function describeRSError(error: IRSErrorDescription): string {
switch (error.errorType) { switch (error.errorType) {
case RSErrorType.unknownSymbol:
return `Неизвестный символ: ${error.params[0]}`;
case RSErrorType.syntax: case RSErrorType.syntax:
return 'Неопределенная синтаксическая ошибка'; return 'Неопределенная синтаксическая ошибка';
case RSErrorType.missingParanthesis: case RSErrorType.missingParanthesis:

View File

@ -14,4 +14,32 @@ export function trimString(target: string, maxLen: number): string {
} else { } else {
return target.substring(0, maxLen) + '...'; return target.substring(0, maxLen) + '...';
} }
} }
/**
* Wrapper class for generalized text matching.
*
* If possible create regexp, otherwise use symbol matching.
*/
export class TextMatcher {
protected query: RegExp | string
constructor(query: string, isPlainText?: boolean, isCaseSensitive?: boolean) {
if (isPlainText) {
query = query.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
}
try {
this.query = new RegExp(query, isCaseSensitive ? '' : 'i');
} catch(exception: unknown) {
this.query = query;
}
}
test(text: string): boolean {
if (typeof this.query === 'string') {
return text.indexOf(this.query) !== -1;
} else {
return !!text.match(this.query);
}
}
}