#126 - Allow escaping the . (dot) character to remove ambiguity with the ... wildcard
- simplistic implementation - use `./...` syntax to remove ambiguity of `....`
This commit is contained in:
parent
f5fafc184f
commit
e0208e2793
|
@ -530,38 +530,49 @@ describe('SortingSpecProcessor', () => {
|
|||
const txtInputThreeDotsCases: string = `
|
||||
target-folder: AAA
|
||||
...
|
||||
\\DOT...
|
||||
....
|
||||
...\\DOT
|
||||
\\DOT...\\DOT
|
||||
..\\DOT...
|
||||
//\\......\\.
|
||||
// Only in the below scenario the / is treated as empty-separator and swallowed
|
||||
./...
|
||||
// Below tricky and not obvious cases
|
||||
../...
|
||||
.../..
|
||||
../...S
|
||||
S.../..
|
||||
S../...S
|
||||
`
|
||||
|
||||
const expectedSortSpecForThreeDotsCases: { [key: string]: CustomSortSpec } = {
|
||||
"AAA": {
|
||||
groups: [{
|
||||
type: CustomSortGroupType.MatchAll
|
||||
},{
|
||||
regexPrefix: { regex: /^\./i },
|
||||
type: CustomSortGroupType.ExactPrefix
|
||||
},{
|
||||
exactSuffix: '.',
|
||||
type: CustomSortGroupType.ExactSuffix
|
||||
},{
|
||||
regexSuffix: { regex: /\.$/i },
|
||||
exactPrefix: '.',
|
||||
type: CustomSortGroupType.ExactPrefix
|
||||
},{
|
||||
exactPrefix: '..',
|
||||
type: CustomSortGroupType.ExactPrefix
|
||||
},{
|
||||
exactSuffix: '/..',
|
||||
type: CustomSortGroupType.ExactSuffix
|
||||
},{
|
||||
regexPrefix: { regex: /^\./i },
|
||||
regexSuffix: { regex: /\.$/i },
|
||||
exactPrefix: '..',
|
||||
exactSuffix: 'S',
|
||||
type: CustomSortGroupType.ExactHeadAndTail
|
||||
},{
|
||||
regexPrefix: { regex: /^\.\.\./i },
|
||||
type: CustomSortGroupType.ExactPrefix
|
||||
exactPrefix: 'S',
|
||||
exactSuffix: '/..',
|
||||
type: CustomSortGroupType.ExactHeadAndTail
|
||||
},{
|
||||
exactPrefix: 'S..',
|
||||
exactSuffix: 'S',
|
||||
type: CustomSortGroupType.ExactHeadAndTail
|
||||
},{
|
||||
type: CustomSortGroupType.Outsiders
|
||||
}],
|
||||
outsidersGroupIdx: 6,
|
||||
outsidersGroupIdx: 8,
|
||||
targetFoldersPaths: ['AAA']
|
||||
}
|
||||
}
|
||||
|
@ -2839,6 +2850,78 @@ describe('convertPlainStringSortingGroupSpecToArraySpec', () => {
|
|||
'...', 'tion. !!!'
|
||||
])
|
||||
})
|
||||
it('should recognize four dots escaper - variant 0', () => {
|
||||
const s = './...'
|
||||
expect(processor.convertPlainStringSortingGroupSpecToArraySpec(s)).toEqual([
|
||||
'.', '...'
|
||||
])
|
||||
})
|
||||
it('should recognize four dots escaper - variant 1', () => {
|
||||
const s = '../...'
|
||||
expect(processor.convertPlainStringSortingGroupSpecToArraySpec(s)).toEqual([
|
||||
'..', '...'
|
||||
])
|
||||
})
|
||||
it('should recognize four dots escaper - variant 2', () => {
|
||||
const s = './...Some'
|
||||
expect(processor.convertPlainStringSortingGroupSpecToArraySpec(s)).toEqual([
|
||||
'.', '...', 'Some'
|
||||
])
|
||||
})
|
||||
it('should recognize four dots escaper - variant 3', () => {
|
||||
const s = 'Some./...'
|
||||
expect(processor.convertPlainStringSortingGroupSpecToArraySpec(s)).toEqual([
|
||||
'Some.','...'
|
||||
])
|
||||
})
|
||||
it('should recognize four dots escaper - variant 3a', () => {
|
||||
const s = 'Some./.....'
|
||||
expect(processor.convertPlainStringSortingGroupSpecToArraySpec(s)).toEqual([
|
||||
'Some./..','...'
|
||||
])
|
||||
})
|
||||
it('should recognize four dots escaper - variant 3b', () => {
|
||||
const s = 'Some./.....X'
|
||||
expect(processor.convertPlainStringSortingGroupSpecToArraySpec(s)).toEqual([
|
||||
'Some.','...', '..X'
|
||||
])
|
||||
})
|
||||
it('should recognize four dots escaper - variant 4', () => {
|
||||
const s = 'Some./...Some'
|
||||
expect(processor.convertPlainStringSortingGroupSpecToArraySpec(s)).toEqual([
|
||||
'Some.','...', 'Some'
|
||||
])
|
||||
})
|
||||
it('should recognize four dots escaper - tricky variant 4', () => {
|
||||
const s = 'Some./... haha ...Some'
|
||||
expect(processor.convertPlainStringSortingGroupSpecToArraySpec(s)).toEqual([
|
||||
'Some.','...', ' haha ...Some'
|
||||
])
|
||||
})
|
||||
it('should recognize four dots escaper - tricky variant 5', () => {
|
||||
const s = 'S.../..'
|
||||
expect(processor.convertPlainStringSortingGroupSpecToArraySpec(s)).toEqual([
|
||||
'S','...', '/..'
|
||||
])
|
||||
})
|
||||
it('should NOT recognize four dots escaper - tricky variant 1', () => {
|
||||
const s = 'Some... haha ./...Some'
|
||||
expect(processor.convertPlainStringSortingGroupSpecToArraySpec(s)).toEqual([
|
||||
'Some','...', ' haha ./...Some'
|
||||
])
|
||||
})
|
||||
it('should NOT recognize four dots escaper - tricky variant 2', () => {
|
||||
const s = 'Some... haha .../...Some'
|
||||
expect(processor.convertPlainStringSortingGroupSpecToArraySpec(s)).toEqual([
|
||||
'Some', '...', ' haha .../...Some'
|
||||
])
|
||||
})
|
||||
it('should NOT recognize four dots escaper - tricky variant 3', () => {
|
||||
const s = '.../...'
|
||||
expect(processor.convertPlainStringSortingGroupSpecToArraySpec(s)).toEqual([
|
||||
'...', '/...'
|
||||
])
|
||||
})
|
||||
it('should recognize some edge case', () => {
|
||||
const s = 'Edge...... ... ..... ... eee?'
|
||||
expect(processor.convertPlainStringSortingGroupSpecToArraySpec(s)).toEqual([
|
||||
|
|
|
@ -98,6 +98,10 @@ const ContextFreeProblems = new Set<ProblemCode>([
|
|||
const ThreeDots = '...';
|
||||
const ThreeDotsLength = ThreeDots.length;
|
||||
|
||||
const AmbigueFourDotsEscaper = './...'
|
||||
const AmbigueFourDotsEscaperLength = AmbigueFourDotsEscaper.length
|
||||
const AmbigueFourDotsEscaperOverlap = 1 // Number of leading chars in the Escaper to retain in original string
|
||||
|
||||
interface CustomSortOrderAscDescPair {
|
||||
asc: CustomSortOrder
|
||||
desc: CustomSortOrder
|
||||
|
@ -334,9 +338,6 @@ const CompoundNumberDashRegexSymbol: string = '\\-d+' // Compound number with d
|
|||
const WordInASCIIRegexSymbol: string = '\\a+'
|
||||
const WordInAnyLanguageRegexSymbol: string = '\\A+'
|
||||
|
||||
// _1_ prefix indicates a lexeme which includes another lexeme and thus has to become first-to-scan
|
||||
const _1_InlineRegexSymbol_Dot: string = '\\DOT'
|
||||
|
||||
const InlineRegexSymbol_Digit1: string = '\\d'
|
||||
const InlineRegexSymbol_Digit2: string = '\\[0-9]'
|
||||
const InlineRegexSymbol_0_to_3: string = '\\[0-3]'
|
||||
|
@ -364,7 +365,6 @@ const sortingSymbolsArr: Array<string> = [
|
|||
const sortingSymbolsRegex = new RegExp(sortingSymbolsArr.join('|'), 'gi')
|
||||
|
||||
const inlineRegexSymbolsArrEscapedForRegex: Array<string> = [
|
||||
escapeRegexUnsafeCharacters(_1_InlineRegexSymbol_Dot),
|
||||
escapeRegexUnsafeCharacters(InlineRegexSymbol_Digit1),
|
||||
escapeRegexUnsafeCharacters(InlineRegexSymbol_Digit2),
|
||||
escapeRegexUnsafeCharacters(InlineRegexSymbol_0_to_3),
|
||||
|
@ -380,7 +380,6 @@ interface RegexExpr {
|
|||
|
||||
// Don't be confused if the source lexeme is equal to the resulting regex piece, logically these two distinct spaces
|
||||
const inlineRegexSymbolsToRegexExpressionsArr: { [key: string]: RegexExpr} = {
|
||||
[_1_InlineRegexSymbol_Dot]: {regexExpr: '\\.'},
|
||||
[InlineRegexSymbol_Digit1]: {regexExpr: '\\d'},
|
||||
[InlineRegexSymbol_Digit2]: {regexExpr: '[0-9]'},
|
||||
[InlineRegexSymbol_0_to_3]: {regexExpr: '[0-3]'},
|
||||
|
@ -1559,7 +1558,7 @@ export class SortingSpecProcessor {
|
|||
[Attribute.OrderUnspecified]: this.validateOrderAttrValue.bind(this)
|
||||
}
|
||||
|
||||
convertPlainStringSortingGroupSpecToArraySpec = (spec: string): Array<string> => {
|
||||
convertPlainStringSortingGroupSpecToArraySpec = (spec: string): Array<string> => {
|
||||
spec = spec.trim()
|
||||
if (isThreeDots(spec)) {
|
||||
return [ThreeDots]
|
||||
|
@ -1568,16 +1567,30 @@ export class SortingSpecProcessor {
|
|||
return [ThreeDots, spec.substring(ThreeDotsLength)];
|
||||
}
|
||||
if (spec.endsWith(ThreeDots)) {
|
||||
return [spec.substring(0, spec.length - ThreeDotsLength), ThreeDots];
|
||||
if (spec.endsWith(AmbigueFourDotsEscaper)) {
|
||||
return [spec.substring(0, spec.length - AmbigueFourDotsEscaperLength + AmbigueFourDotsEscaperOverlap), ThreeDots];
|
||||
} else {
|
||||
return [spec.substring(0, spec.length - ThreeDotsLength), ThreeDots];
|
||||
}
|
||||
}
|
||||
|
||||
const idx = spec.indexOf(ThreeDots);
|
||||
const idxOfAmbigueFourDotsEscaper = spec.indexOf(AmbigueFourDotsEscaper)
|
||||
if (idx > 0) {
|
||||
return [
|
||||
spec.substring(0, idx),
|
||||
ThreeDots,
|
||||
spec.substring(idx + ThreeDotsLength)
|
||||
];
|
||||
if (idxOfAmbigueFourDotsEscaper >= 0 &&
|
||||
idxOfAmbigueFourDotsEscaper === idx - (AmbigueFourDotsEscaperLength - ThreeDotsLength) ) {
|
||||
return [
|
||||
spec.substring(0, idxOfAmbigueFourDotsEscaper + AmbigueFourDotsEscaperOverlap),
|
||||
ThreeDots,
|
||||
spec.substring(idx + ThreeDotsLength)
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
spec.substring(0, idx),
|
||||
ThreeDots,
|
||||
spec.substring(idx + ThreeDotsLength)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Unrecognized, treat as exact match
|
||||
|
|
Loading…
Reference in New Issue