···11# string-sameness
2233-Generate a score that represents how closely the same two strings are. The comparison function uses an average of:
44-55-* [Dice's Coefficient](https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient)
66-* [Cosine Similarity](https://en.wikipedia.org/wiki/Cosine_similarity)
77-* [Levenshtein Distance](https://en.wikipedia.org/wiki/Levenshtein_distance)
33+Generate scores that represents how similar two strings are based on different string comparison algorithms.
8499-weighted by the length of the content being compared (more weight for longer content).
55+Scores from all used algorithms are averaged and then weighted by the length of the content being compared (more weight for longer content).
106117The sameness is then given a **score of 0 to 100.**
128139* 0 => Totally unique pieces of content
1410* 100 => Identical content
15111616-## Install/Usage
1212+# Install/Usage
17131814```
1915npm install @foxxmd/string-sameness
···24202521const result = stringSameness('This is one sentence', 'This is another sentence');
2622console.log(result);
2727-// {
2828-// "scores": {
2929-// "dice": 66.66,
3030-// "cosine": 75,
3131-// "leven": 79.16
3232-// },
3333-// "highScore": 73.61,
3434-// "highScoreWeighted": 83.58
3535-// }
2323+//{
2424+// "strategies": {
2525+// "dice": {
2626+// "score": 66.66666666666666
2727+// },
2828+// "leven": {
2929+// "distance": 5,
3030+// "score": 79.16666666666666
3131+// },
3232+// "cosine": {
3333+// "score": 75
3434+// }
3535+// },
3636+// "highScore": 73.6111111111111,
3737+// "highScoreWeighted": 83.58977247888106
3838+//}
3639```
37403838-### Normalization
4141+# Options
4242+4343+An optional third argument can be provided to `stringSameness` to customize how strings are normalized before comparison and what strategies are used for comparison.
4444+4545+## Strategies
4646+4747+Pass a list of `ComparisonStrategy` objects using `{strategies: []}` to define which string comparisons should be performed on the given strings.
39484040-A third argument may be passed to `stringSameness` to provide a list of functions to apply to the strings to compare. When not explicitly provided a default set of functions is applied to normalize the strings (to remove trivial differences):
4949+The average of the scores from all passed strategies is returned as `highScore` (and `highScoreWeighted`) from `stringSameness()`
5050+5151+When no strategies are explicitly passed a default set of strategies is used, found in `@foxxmd/string-sameness/strategies`:
5252+5353+* [Dice's Coefficient](https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient) in [`diceSimilarities.ts`](/src/matchingStrategies/diceSimilarity.ts)
5454+* [Cosine Similarity](https://en.wikipedia.org/wiki/Cosine_similarity) in [`cosineSimilarities.ts`](/src/matchingStrategies/cosineSimilarity.ts)
5555+* [Levenshtein Distance](https://en.wikipedia.org/wiki/Levenshtein_distance) in [`levenSimilarities.ts`](/src/matchingStrategies/levenSimilarity.ts)
5656+5757+### Bring Your Own Strategy
5858+5959+Use your own strategy by creating an object that conforms to `ComparisonStrategy`:
6060+6161+```ts
6262+export interface ComparisonStrategy {
6363+ /**
6464+ * The name of this strategy
6565+ * */
6666+ name: string
6767+ /**
6868+ * A function that accepts two string arguments and returns a number between 0 and 100 signifying how closely similar the strings are:
6969+ * 0 => not similar at all
7070+ * 100 => identical
7171+ * */
7272+ strategy: (strA: string, strB: string) => number
7373+ /**
7474+ * An optional function that accepts two string arguments and returns whether this strategy should be used
7575+ * */
7676+ isValid?: (strA: string, strB: string) => boolean
7777+}
7878+```
7979+8080+Example of using your own strategy with the defaults:
8181+8282+```ts
8383+import {stringSameness} from "@foxxmd/string-sameness";
8484+import {ComparisonStrategy, levenStrategy, cosineStrategy, diceStrategy} from "@foxxmd/string-sameness/strategies";
8585+8686+const myStrat: ComparisonStrategy = {
8787+ name: 'MyCoolStrat',
8888+ strategy: (valA: string, valB: string) => {
8989+ const a = valA.concat(valB);
9090+ return a.length;
9191+ },
9292+}
9393+const strats = [
9494+ levenStrategy,
9595+ cosineStrategy,
9696+ diceStrategy,
9797+ myStrat
9898+]
9999+100100+const result = stringSameness('This is one sentence', 'This is another sentence', {strategies: strats});
101101+```
102102+103103+## Normalization
104104+105105+Pass a list of functions using `{transforms: []}` to transform the strings before comparison. When not explicitly provided a default set of functions is applied to normalize the strings (to remove trivial differences):
4110642107* convert to lowercase
43108* trim (remove whitespace at beginning/end)
···57122 (str) => str.replace(/[aeiou]/ig, 'e')
58123]
591246060-const result = stringSameness('This is one sentence', 'This is another sentence', myFuncs);
125125+const result = stringSameness('This is one sentence', 'This is another sentence', {transforms: myFuncs});
126126+```
127127+128128+## Factory
129129+130130+For convenience, a factory function is also provided:
131131+132132+```ts
133133+import {createStringSameness} from "@foxxmd/string-sameness";
134134+import {levenStrategy} from "@foxxmd/string-sameness/strategies";
135135+import {myTransforms, myStrats} from './util';
136136+137137+// sets the default object to used with the third argument for `stringSameness`
138138+const myCompare = createStringSameness({transforms: myTransforms, strategies: myStrats});
139139+140140+// uses myTransforms and myStrats
141141+const plainResult = myCompare('This is one sentence', 'This is another sentence');
142142+143143+// override your defaults using the third argument like normal
144144+const overrideResults = myCompare('This is one sentence', 'This is another sentence', {strategies: [levenStrategy]});
61145```
+36
dist/atomic.d.ts
···11+export interface StringComparisonOptions {
22+ transforms?: ((str: string) => string)[];
33+ strategies?: ComparisonStrategy[];
44+}
55+export interface StringSamenessResult {
66+ strategies: {
77+ [key: string]: ComparisonStrategyResult;
88+ };
99+ highScore: number;
1010+ highScoreWeighted: number;
1111+}
1212+export interface ComparisonStrategyResultObject {
1313+ score: number;
1414+ [key: string]: any;
1515+}
1616+export interface ComparisonStrategyResult extends ComparisonStrategyResultObject {
1717+}
1818+export interface NamedComparisonStrategyObjectResult extends ComparisonStrategyResultObject {
1919+ name: string;
2020+}
2121+export type ComparisonStrategyResultValue = number | ComparisonStrategyResultObject;
2222+export type StrategyFunc = (strA: string, strB: string) => ComparisonStrategyResultValue;
2323+export interface ComparisonStrategy {
2424+ /**
2525+ * The name of this strategy
2626+ * */
2727+ name: string;
2828+ /**
2929+ * A function that accepts two string arguments and returns a number
3030+ * */
3131+ strategy: StrategyFunc;
3232+ /**
3333+ * An optional function that accepts to string arguments and returns whether this strategy should be used
3434+ * */
3535+ isValid?: (strA: string, strB: string) => boolean;
3636+}