Skip to content

Commit

Permalink
Merge pull request #7 from paperhive/transform-ranges
Browse files Browse the repository at this point in the history
Transform ranges
  • Loading branch information
andrenarchy authored Nov 30, 2016
2 parents fe27c26 + dbe8b2b commit 7cebe39
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 1 deletion.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,16 @@ backTransformRange({position: 6, length: 10}, transformations);
}]
```

### search(searchStr)
- returns ranges of `searchStr` in a search index
```
const index = new SearchIndex('this is a test');
index.search('is a test');
=> [{position: 6, length: 10}]
const index = new SearchIndex(' hello world , HELLO WORLD ');
index.search('hello world');
=> [{position: 2, length: 13}, {position: 19, length: 14}]
```
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "srch",
"version": "1.1.0",
"version": "1.2.0",
"description": "full text search",
"main": "src/index.js",
"scripts": {
Expand Down
51 changes: 51 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,54 @@ exports.backTransformRange = function backTransformRange(range, transformations)
if (rangePosition !== 0) throw new Error('Out of range');
return output;
};

function transformLowercase(str) {
return {
str: str.toLowerCase(),
mapping: [{transformed: str.length, original: str.length}],
};
}

function transform(transformations, str) {
let transformedStr = str;
const mappings = [];
transformations.forEach((transformation) => {
const {str: newStr, mapping} = transformation(transformedStr);
transformedStr = newStr;
mappings.push(mapping);
});
return {transformedStr, mapping: mappings};
}


exports.SearchIndex = class SearchIndex {
constructor(str) {
this.transformations = [exports.transformSpaces, transformLowercase];

const {transformedStr, mapping} = transform(this.transformations, str);
this.transformedStr = transformedStr;
this.mappings = mapping;
}

search(searchStr) {
const {transformedStr} = transform(this.transformations, searchStr);
if (transformedStr.length === 0) throw new Error('transformed string is empty');

// end position points to the last character
let startPositions = exports.findPositions(this.transformedStr, transformedStr);
let endPositions = startPositions.map(position => position + (transformedStr.length - 1));

// note: slice() copies the array so reverse() can alter the array
this.mappings.slice().reverse().forEach((mapping) => {
startPositions = exports.backTransformPositions(startPositions, mapping);
endPositions = exports.backTransformPositions(endPositions, mapping);
});

const ranges = [];
for (let i = 0; i < startPositions.length; i += 1) {
ranges.push({position: startPositions[i], length: (endPositions[i] - startPositions[i]) + 1});
}

return ranges;
}
};
35 changes: 35 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,38 @@ describe('backTransformRange', () => {
.should.throw('Empty transformations');
});
});

describe('SearchIndex', () => {
it('should find ranges', () => {
const index = new srch.SearchIndex('this is a test');
index.search('is a test').should.eql([{position: 6, length: 10}]);
});

it('should find ranges with spaces at the end and beginning', () => {
const index = new srch.SearchIndex(' hello world ');
index.search('hello world').should.eql([{position: 3, length: 12}]);
});

it('should find ranges: transformed string equals original', () => {
const index = new srch.SearchIndex('hello world');
index.search('hello world').should.eql([{position: 0, length: 11}]);
});

it('should find ranges: 2 occurences of searchStr in text', () => {
const index = new srch.SearchIndex('hello world, hello world');
index.search('hello world').should.eql([{position: 0, length: 11}, {position: 13, length: 11}]);
});

it('should find ranges: 2 occurences of searchStr in text with spaces', () => {
const index = new srch.SearchIndex(' hello world , hello world ');
index.search('hello world').should.eql([{position: 2, length: 13}, {position: 19, length: 14}]);
});

it('should find ranges: mixed lower and upper case', () => {
const index = new srch.SearchIndex('TEST test TEst TeSt ');
index.search('test').should.eql([
{position: 0, length: 4}, {position: 5, length: 4},
{position: 10, length: 4}, {position: 15, length: 4},
]);
});
});

0 comments on commit 7cebe39

Please sign in to comment.