captcha-ocr 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/README.md +223 -0
- package/README.zh-CN.md +223 -0
- package/dist/arithmetic-CUs9apP8.d.cts +113 -0
- package/dist/arithmetic-CUs9apP8.d.ts +113 -0
- package/dist/index.cjs +475 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +40 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.js +423 -0
- package/dist/index.js.map +1 -0
- package/dist/rules/arithmetic.cjs +176 -0
- package/dist/rules/arithmetic.cjs.map +1 -0
- package/dist/rules/arithmetic.d.cts +1 -0
- package/dist/rules/arithmetic.d.ts +1 -0
- package/dist/rules/arithmetic.js +145 -0
- package/dist/rules/arithmetic.js.map +1 -0
- package/package.json +66 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// src/rules/arithmetic.ts
|
|
2
|
+
var DEFAULT_OPERATORS = {
|
|
3
|
+
"+": {
|
|
4
|
+
evaluate: (left, right) => left + right
|
|
5
|
+
},
|
|
6
|
+
"-": {
|
|
7
|
+
evaluate: (left, right) => left - right
|
|
8
|
+
},
|
|
9
|
+
"*": {
|
|
10
|
+
aliases: ["x", "X", "\xD7", "\xB7"],
|
|
11
|
+
evaluate: (left, right) => left * right
|
|
12
|
+
},
|
|
13
|
+
"/": {
|
|
14
|
+
aliases: ["\xF7"],
|
|
15
|
+
evaluate: (left, right) => left / right,
|
|
16
|
+
validate: (left, right) => right === 0 ? {
|
|
17
|
+
code: "DIVISION_BY_ZERO",
|
|
18
|
+
message: "\u9664\u6570\u4E0D\u80FD\u4E3A 0"
|
|
19
|
+
} : null
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
function createArithmeticRule(options = {}) {
|
|
23
|
+
const operators = options.operators ?? DEFAULT_OPERATORS;
|
|
24
|
+
const aliasToOperator = /* @__PURE__ */ new Map();
|
|
25
|
+
for (const [symbol, definition] of Object.entries(operators)) {
|
|
26
|
+
aliasToOperator.set(symbol, symbol);
|
|
27
|
+
for (const alias of definition.aliases ?? []) {
|
|
28
|
+
aliasToOperator.set(alias, symbol);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const operatorPattern = Object.keys(operators).sort((left, right) => right.length - left.length).map(escapeRegExp).join("|");
|
|
32
|
+
const expressionPattern = new RegExp(
|
|
33
|
+
`^(\\d{1,6})(${operatorPattern})(\\d{1,6})(?:=)?\\??$`
|
|
34
|
+
);
|
|
35
|
+
const normalize = (text) => {
|
|
36
|
+
let normalized = text.normalize("NFKC").replace(/\s+/g, "");
|
|
37
|
+
for (const [alias, symbol] of [...aliasToOperator.entries()].sort(
|
|
38
|
+
([left], [right]) => right.length - left.length
|
|
39
|
+
)) {
|
|
40
|
+
normalized = normalized.split(alias).join(symbol);
|
|
41
|
+
}
|
|
42
|
+
normalized = normalized.replace(/[Oo]/g, "0").replace(/[Il|]/g, "1");
|
|
43
|
+
return normalized;
|
|
44
|
+
};
|
|
45
|
+
const parse = (text) => {
|
|
46
|
+
const normalized = normalize(text);
|
|
47
|
+
const match = normalized.match(expressionPattern);
|
|
48
|
+
if (!match) {
|
|
49
|
+
return {
|
|
50
|
+
ok: false,
|
|
51
|
+
normalized,
|
|
52
|
+
error: {
|
|
53
|
+
code: "EXPRESSION_NOT_MATCHED",
|
|
54
|
+
message: "\u65E0\u6CD5\u8BC6\u522B\u4E3A\u201C\u6570\u5B57 \u8FD0\u7B97\u7B26 \u6570\u5B57 =?\u201D\u683C\u5F0F"
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const parsed = {
|
|
59
|
+
left: Number(match[1]),
|
|
60
|
+
operator: match[2],
|
|
61
|
+
right: Number(match[3])
|
|
62
|
+
};
|
|
63
|
+
const validationError = operators[parsed.operator].validate?.(parsed.left, parsed.right) ?? null;
|
|
64
|
+
if (validationError) {
|
|
65
|
+
return {
|
|
66
|
+
ok: false,
|
|
67
|
+
normalized,
|
|
68
|
+
error: validationError
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
ok: true,
|
|
73
|
+
normalized,
|
|
74
|
+
expression: `${parsed.left}${parsed.operator}${parsed.right}`,
|
|
75
|
+
parsed
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
return {
|
|
79
|
+
id: options.id ?? "arithmetic-v1",
|
|
80
|
+
normalize,
|
|
81
|
+
parse,
|
|
82
|
+
evaluate: (parsed) => operators[parsed.operator].evaluate(parsed.left, parsed.right)
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
var arithmeticRule = createArithmeticRule();
|
|
86
|
+
function normalizeOcrText(text) {
|
|
87
|
+
return arithmeticRule.normalize(text);
|
|
88
|
+
}
|
|
89
|
+
function parseExpression(text) {
|
|
90
|
+
const parsed = arithmeticRule.parse(text);
|
|
91
|
+
if (!parsed.ok) {
|
|
92
|
+
return {
|
|
93
|
+
ok: false,
|
|
94
|
+
normalized: parsed.normalized,
|
|
95
|
+
expression: null,
|
|
96
|
+
answer: null,
|
|
97
|
+
error: parsed.error
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
ok: true,
|
|
102
|
+
normalized: parsed.normalized,
|
|
103
|
+
expression: parsed.expression,
|
|
104
|
+
answer: arithmeticRule.evaluate(parsed.parsed),
|
|
105
|
+
error: null
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function calculate(left, operator, right) {
|
|
109
|
+
const definition = DEFAULT_OPERATORS[operator];
|
|
110
|
+
if (!definition) {
|
|
111
|
+
throw new Error(`\u4E0D\u652F\u6301\u7684\u8FD0\u7B97\u7B26: ${operator}`);
|
|
112
|
+
}
|
|
113
|
+
const validationError = definition.validate?.(left, right);
|
|
114
|
+
if (validationError) {
|
|
115
|
+
throw new Error(validationError.message);
|
|
116
|
+
}
|
|
117
|
+
return definition.evaluate(left, right);
|
|
118
|
+
}
|
|
119
|
+
var arithmeticProfile = {
|
|
120
|
+
id: "arithmetic-v1",
|
|
121
|
+
ocr: {
|
|
122
|
+
language: "eng",
|
|
123
|
+
whitelist: "0123456789+-*/=?xX\xD7\xF7",
|
|
124
|
+
pageSegMode: 7,
|
|
125
|
+
preserveInterwordSpaces: false
|
|
126
|
+
},
|
|
127
|
+
preprocess: {
|
|
128
|
+
scale: 4,
|
|
129
|
+
thresholds: [160, 120, 180, 200]
|
|
130
|
+
},
|
|
131
|
+
rule: arithmeticRule
|
|
132
|
+
};
|
|
133
|
+
function escapeRegExp(value) {
|
|
134
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
135
|
+
}
|
|
136
|
+
export {
|
|
137
|
+
DEFAULT_OPERATORS,
|
|
138
|
+
arithmeticProfile,
|
|
139
|
+
arithmeticRule,
|
|
140
|
+
calculate,
|
|
141
|
+
createArithmeticRule,
|
|
142
|
+
normalizeOcrText,
|
|
143
|
+
parseExpression
|
|
144
|
+
};
|
|
145
|
+
//# sourceMappingURL=arithmetic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/rules/arithmetic.ts"],"sourcesContent":["import type {\n CaptchaRule,\n CaptchaProfile,\n RecognitionError,\n RuleParseResult\n} from '../types.js';\n\nexport interface ArithmeticExpression {\n left: number;\n operator: string;\n right: number;\n}\n\nexport interface ArithmeticOperator {\n aliases?: string[];\n evaluate(left: number, right: number): number;\n validate?(left: number, right: number): RecognitionError | null;\n}\n\nexport const DEFAULT_OPERATORS: Record<string, ArithmeticOperator> = {\n '+': {\n evaluate: (left, right) => left + right\n },\n '-': {\n evaluate: (left, right) => left - right\n },\n '*': {\n aliases: ['x', 'X', '×', '·'],\n evaluate: (left, right) => left * right\n },\n '/': {\n aliases: ['÷'],\n evaluate: (left, right) => left / right,\n validate: (left, right) =>\n right === 0\n ? {\n code: 'DIVISION_BY_ZERO',\n message: '除数不能为 0'\n }\n : null\n }\n};\n\nexport interface ArithmeticRuleOptions {\n id?: string;\n whitelist?: string;\n operators?: Record<string, ArithmeticOperator>;\n}\n\nexport function createArithmeticRule(\n options: ArithmeticRuleOptions = {}\n): CaptchaRule<ArithmeticExpression, number> {\n const operators = options.operators ?? DEFAULT_OPERATORS;\n const aliasToOperator = new Map<string, string>();\n\n for (const [symbol, definition] of Object.entries(operators)) {\n aliasToOperator.set(symbol, symbol);\n for (const alias of definition.aliases ?? []) {\n aliasToOperator.set(alias, symbol);\n }\n }\n\n const operatorPattern = Object.keys(operators)\n .sort((left, right) => right.length - left.length)\n .map(escapeRegExp)\n .join('|');\n const expressionPattern = new RegExp(\n `^(\\\\d{1,6})(${operatorPattern})(\\\\d{1,6})(?:=)?\\\\??$`\n );\n\n const normalize = (text: string): string => {\n let normalized = text.normalize('NFKC').replace(/\\s+/g, '');\n for (const [alias, symbol] of [...aliasToOperator.entries()].sort(\n ([left], [right]) => right.length - left.length\n )) {\n normalized = normalized.split(alias).join(symbol);\n }\n normalized = normalized.replace(/[Oo]/g, '0').replace(/[Il|]/g, '1');\n return normalized;\n };\n\n const parse = (text: string): RuleParseResult<ArithmeticExpression> => {\n const normalized = normalize(text);\n const match = normalized.match(expressionPattern);\n\n if (!match) {\n return {\n ok: false,\n normalized,\n error: {\n code: 'EXPRESSION_NOT_MATCHED',\n message: '无法识别为“数字 运算符 数字 =?”格式'\n }\n };\n }\n\n const parsed: ArithmeticExpression = {\n left: Number(match[1]),\n operator: match[2],\n right: Number(match[3])\n };\n const validationError =\n operators[parsed.operator].validate?.(parsed.left, parsed.right) ?? null;\n\n if (validationError) {\n return {\n ok: false,\n normalized,\n error: validationError\n };\n }\n\n return {\n ok: true,\n normalized,\n expression: `${parsed.left}${parsed.operator}${parsed.right}`,\n parsed\n };\n };\n\n return {\n id: options.id ?? 'arithmetic-v1',\n normalize,\n parse,\n evaluate: (parsed) =>\n operators[parsed.operator].evaluate(parsed.left, parsed.right)\n };\n}\n\nexport const arithmeticRule = createArithmeticRule();\n\nexport interface LegacyExpressionSuccess {\n ok: true;\n normalized: string;\n expression: string;\n answer: number;\n error: null;\n}\n\nexport interface LegacyExpressionFailure {\n ok: false;\n normalized: string;\n expression: null;\n answer: null;\n error: RecognitionError;\n}\n\nexport type LegacyExpressionResult =\n | LegacyExpressionSuccess\n | LegacyExpressionFailure;\n\nexport function normalizeOcrText(text: string): string {\n return arithmeticRule.normalize(text);\n}\n\nexport function parseExpression(text: string): LegacyExpressionResult {\n const parsed = arithmeticRule.parse(text);\n if (!parsed.ok) {\n return {\n ok: false,\n normalized: parsed.normalized,\n expression: null,\n answer: null,\n error: parsed.error\n };\n }\n\n return {\n ok: true,\n normalized: parsed.normalized,\n expression: parsed.expression,\n answer: arithmeticRule.evaluate(parsed.parsed),\n error: null\n };\n}\n\nexport function calculate(\n left: number,\n operator: string,\n right: number\n): number {\n const definition = DEFAULT_OPERATORS[operator];\n if (!definition) {\n throw new Error(`不支持的运算符: ${operator}`);\n }\n const validationError = definition.validate?.(left, right);\n if (validationError) {\n throw new Error(validationError.message);\n }\n return definition.evaluate(left, right);\n}\n\nexport const arithmeticProfile: CaptchaProfile<\n ArithmeticExpression,\n number\n> = {\n id: 'arithmetic-v1',\n ocr: {\n language: 'eng',\n whitelist: '0123456789+-*/=?xX×÷',\n pageSegMode: 7,\n preserveInterwordSpaces: false\n },\n preprocess: {\n scale: 4,\n thresholds: [160, 120, 180, 200]\n },\n rule: arithmeticRule\n};\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "captcha-ocr",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "TypeScript captcha OCR recognizer with configurable profiles and rules",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.cjs",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"author": "wisen",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js",
|
|
15
|
+
"require": "./dist/index.cjs"
|
|
16
|
+
},
|
|
17
|
+
"./rules/arithmetic": {
|
|
18
|
+
"types": "./dist/rules/arithmetic.d.ts",
|
|
19
|
+
"import": "./dist/rules/arithmetic.js",
|
|
20
|
+
"require": "./dist/rules/arithmetic.cjs"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist/index.*",
|
|
25
|
+
"dist/arithmetic-*.d.ts",
|
|
26
|
+
"dist/arithmetic-*.d.cts",
|
|
27
|
+
"dist/rules/*",
|
|
28
|
+
"README.md",
|
|
29
|
+
"README.zh-CN.md",
|
|
30
|
+
"CHANGELOG.md"
|
|
31
|
+
],
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"registry": "https://registry.npmjs.org/",
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=20"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"sharp": "^0.35.3",
|
|
41
|
+
"tesseract.js": "^5.1.1"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^22.10.2",
|
|
45
|
+
"changelogen": "^0.6.2",
|
|
46
|
+
"tsup": "^8.3.5",
|
|
47
|
+
"tsx": "^4.19.2",
|
|
48
|
+
"typescript": "^5.7.2"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "tsup",
|
|
52
|
+
"start": "pnpm build && node dist/bin/server.cjs",
|
|
53
|
+
"dev": "tsx bin/server.ts",
|
|
54
|
+
"cli": "pnpm build && node dist/bin/cli.cjs",
|
|
55
|
+
"test": "tsx --test test/*.test.ts",
|
|
56
|
+
"pack:check": "pnpm build && pnpm pack --pack-destination ./tmp",
|
|
57
|
+
"release:check": "pnpm test && pnpm exec tsc --noEmit && pnpm run pack:check",
|
|
58
|
+
"release": "pnpm run release:auto",
|
|
59
|
+
"release:auto": "pnpm run release:check && changelogen --release --clean --hideAuthorEmail && pnpm run release:publish",
|
|
60
|
+
"release:patch": "pnpm run release:check && changelogen --release --clean --patch --hideAuthorEmail && pnpm run release:publish",
|
|
61
|
+
"release:base": "pnpm run release:check && changelogen --release --clean --minor --hideAuthorEmail && pnpm run release:publish",
|
|
62
|
+
"release:minor": "pnpm run release:base",
|
|
63
|
+
"release:major": "pnpm run release:check && changelogen --release --clean --major --hideAuthorEmail && pnpm run release:publish",
|
|
64
|
+
"release:publish": "pnpm publish --registry https://registry.npmjs.org/ --access public"
|
|
65
|
+
}
|
|
66
|
+
}
|