@valueerror/ltjs-lang-pl 0.0.0-stage → 0.1.1
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/LICENSE +232 -0
- package/NOTICE +9 -0
- package/README.md +25 -2
- package/index.js +8 -0
- package/licenses/LGPL-2.1.txt +504 -0
- package/licenses/resource_pl_README.txt +67 -0
- package/licenses/resource_pl_hunspell_README_en.txt +34 -0
- package/package.json +60 -4
- package/resource-root.js +4 -0
- package/resources/META-INF/org/languagetool/language-module.properties +1 -0
- package/resources/org/languagetool/resource/pl/README.txt +67 -0
- package/resources/org/languagetool/resource/pl/added.txt +5 -0
- package/resources/org/languagetool/resource/pl/added_custom.txt +4 -0
- package/resources/org/languagetool/resource/pl/compounds.txt +1862 -0
- package/resources/org/languagetool/resource/pl/disambiguation.xml +15826 -0
- package/resources/org/languagetool/resource/pl/hunspell/README_en.txt +34 -0
- package/resources/org/languagetool/resource/pl/hunspell/ignore.txt +182 -0
- package/resources/org/languagetool/resource/pl/hunspell/pl_PL.dict +0 -0
- package/resources/org/languagetool/resource/pl/hunspell/pl_PL.info +19 -0
- package/resources/org/languagetool/resource/pl/hunspell/prohibit.txt +14 -0
- package/resources/org/languagetool/resource/pl/hunspell/spelling.txt +144 -0
- package/resources/org/languagetool/resource/pl/multiwords.txt +232 -0
- package/resources/org/languagetool/resource/pl/nie_compar_exceptions.txt +58 -0
- package/resources/org/languagetool/resource/pl/polish.dict +0 -0
- package/resources/org/languagetool/resource/pl/polish.info +38 -0
- package/resources/org/languagetool/resource/pl/polish_synth.dict +0 -0
- package/resources/org/languagetool/resource/pl/polish_synth.info +38 -0
- package/resources/org/languagetool/resource/pl/polish_tags.txt +1095 -0
- package/resources/org/languagetool/resource/pl/removed.txt +4 -0
- package/resources/org/languagetool/resource/pl/removed_custom.txt +4 -0
- package/resources/org/languagetool/rules/pl/bitext.xml +30 -0
- package/resources/org/languagetool/rules/pl/coherency.txt +323 -0
- package/resources/org/languagetool/rules/pl/grammar.xml +31052 -0
- package/resources/org/languagetool/rules/pl/replace.txt +237 -0
- package/src/lang/pl/language/Polish.js +111 -0
- package/src/lang/pl/rules/CompoundRule.js +40 -0
- package/src/lang/pl/rules/DashRule.js +32 -0
- package/src/lang/pl/rules/DateCheckFilter.js +56 -0
- package/src/lang/pl/rules/DecadeSpellingFilter.js +56 -0
- package/src/lang/pl/rules/MorfologikPolishSpellerRule.js +141 -0
- package/src/lang/pl/rules/PolishUnpairedBracketsRule.js +23 -0
- package/src/lang/pl/rules/PolishWordRepeatRule.js +64 -0
- package/src/lang/pl/rules/SimpleReplaceRule.js +63 -0
- package/src/lang/pl/rules/WordCoherencyRule.js +40 -0
- package/src/lang/pl/synthesis/PolishSynthesizer.js +151 -0
- package/src/lang/pl/tagging/PolishHybridDisambiguator.js +25 -0
- package/src/lang/pl/tagging/PolishTagger.js +95 -0
- package/src/lang/pl/tokenizers/PolishWordTokenizer.js +112 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Java: org.languagetool.rules.pl.PolishUnpairedBracketsRule
|
|
2
|
+
import { GenericUnpairedBracketsRule } from '@valueerror/ltjs-core/src/core/rules/GenericUnpairedBracketsRule.js';
|
|
3
|
+
import { Example } from '@valueerror/ltjs-core/src/core/rules/model/Examples.js';
|
|
4
|
+
|
|
5
|
+
const PL_START_SYMBOLS = ['[', '(', '{', '„', '»', '"'];
|
|
6
|
+
const PL_END_SYMBOLS = [']', ')', '}', '”', '«', '"'];
|
|
7
|
+
|
|
8
|
+
// Java: PolishUnpairedBracketsRule
|
|
9
|
+
export class PolishUnpairedBracketsRule extends GenericUnpairedBracketsRule {
|
|
10
|
+
static FQCN = 'org.languagetool.rules.pl.PolishUnpairedBracketsRule';
|
|
11
|
+
|
|
12
|
+
// Java: PolishUnpairedBracketsRule(ResourceBundle,Language)
|
|
13
|
+
constructor(messages) {
|
|
14
|
+
super(messages, PL_START_SYMBOLS, PL_END_SYMBOLS);
|
|
15
|
+
this.addExamplePair(Example.wrong('To jest zdanie z <marker>„</marker>cudzysłowem.'),
|
|
16
|
+
Example.fixed('To jest zdanie z <marker>„</marker>cudzysłowem”.'));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Java: PolishUnpairedBracketsRule#getId()
|
|
20
|
+
getId() {
|
|
21
|
+
return 'PL_UNPAIRED_BRACKETS';
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// Java: org.languagetool.rules.pl.PolishWordRepeatRule
|
|
2
|
+
import { Pattern } from '@valueerror/ltjs-core/src/lib/java/regex/index.js';
|
|
3
|
+
import { AdvancedWordRepeatRule } from '@valueerror/ltjs-core/src/core/rules/AdvancedWordRepeatRule.js';
|
|
4
|
+
import { Example } from '@valueerror/ltjs-core/src/core/rules/model/Examples.js';
|
|
5
|
+
|
|
6
|
+
// Excluded dictionary words.
|
|
7
|
+
const EXC_WORDS = new Set([
|
|
8
|
+
'nie', 'tuż', 'aż', 'to', 'siebie', 'być', 'ani', 'ni', 'albo', 'lub', 'czy', 'bądź', 'jako', 'zł', 'np', 'coraz',
|
|
9
|
+
'bardzo', 'bardziej', 'proc', 'ten', 'jak', 'mln', 'tys', 'swój', 'mój', 'twój', 'nasz', 'wasz', 'i', 'zbyt', 'się',
|
|
10
|
+
]);
|
|
11
|
+
|
|
12
|
+
// Excluded part of speech classes.
|
|
13
|
+
const EXC_POS = Pattern.compile('prep:.*|ppron.*');
|
|
14
|
+
|
|
15
|
+
// Excluded non-words (special symbols, Roman numerals etc.)
|
|
16
|
+
const EXC_NONWORDS = Pattern.compile('"|>|<|&|[0-9].*|'
|
|
17
|
+
+ 'M*(D?C{0,3}|C[DM])(L?X{0,3}|X[LC])(V?I{0,3}|I[VX])$');
|
|
18
|
+
|
|
19
|
+
// Java: PolishWordRepeatRule
|
|
20
|
+
export class PolishWordRepeatRule extends AdvancedWordRepeatRule {
|
|
21
|
+
static FQCN = 'org.languagetool.rules.pl.PolishWordRepeatRule';
|
|
22
|
+
|
|
23
|
+
// Java: PolishWordRepeatRule(ResourceBundle)
|
|
24
|
+
constructor(messages) {
|
|
25
|
+
super(messages);
|
|
26
|
+
this.addExamplePair(Example.wrong('Mówiła długo, bo lubiła robić wszystko <marker>długo</marker>.'),
|
|
27
|
+
Example.fixed('Mówiła długo, bo lubiła robić wszystko <marker>powoli</marker>.'));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Java: PolishWordRepeatRule#getDescription()
|
|
31
|
+
getDescription() {
|
|
32
|
+
return 'Powtórzenia wyrazów w zdaniu (monotonia stylistyczna)';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Java: PolishWordRepeatRule#getExcludedNonWordsPattern()
|
|
36
|
+
getExcludedNonWordsPattern() {
|
|
37
|
+
return EXC_NONWORDS;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Java: PolishWordRepeatRule#getExcludedPos()
|
|
41
|
+
getExcludedPos() {
|
|
42
|
+
return EXC_POS;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Java: PolishWordRepeatRule#getExcludedWordsPattern()
|
|
46
|
+
getExcludedWordsPattern() {
|
|
47
|
+
return EXC_WORDS;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Java: PolishWordRepeatRule#getId()
|
|
51
|
+
getId() {
|
|
52
|
+
return 'PL_WORD_REPEAT';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Java: PolishWordRepeatRule#getMessage()
|
|
56
|
+
getMessage() {
|
|
57
|
+
return 'Powtórzony wyraz w zdaniu';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Java: PolishWordRepeatRule#getShortMessage()
|
|
61
|
+
getShortMessage() {
|
|
62
|
+
return 'Powtórzenie wyrazu';
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// Java: org.languagetool.rules.pl.SimpleReplaceRule
|
|
2
|
+
import { AbstractSimpleReplaceRule } from '@valueerror/ltjs-core/src/core/rules/AbstractSimpleReplaceRule.js';
|
|
3
|
+
import { Category, CategoryId } from '@valueerror/ltjs-core/src/core/rules/model/Category.js';
|
|
4
|
+
import { Example } from '@valueerror/ltjs-core/src/core/rules/model/Examples.js';
|
|
5
|
+
import { ITSIssueType } from '@valueerror/ltjs-core/src/core/rules/model/ITSIssueType.js';
|
|
6
|
+
import { Locale } from '@valueerror/ltjs-core/src/lib/java/Locale.js';
|
|
7
|
+
|
|
8
|
+
let wrongWords = null; // Java: static wrongWords = loadFromPath("/pl/replace.txt")
|
|
9
|
+
const PL_LOCALE = new Locale('pl');
|
|
10
|
+
|
|
11
|
+
// Java: SimpleReplaceRule (pl)
|
|
12
|
+
export class SimpleReplaceRule extends AbstractSimpleReplaceRule {
|
|
13
|
+
static FQCN = 'org.languagetool.rules.pl.SimpleReplaceRule';
|
|
14
|
+
static POLISH_SIMPLE_REPLACE_RULE = 'PL_SIMPLE_REPLACE';
|
|
15
|
+
|
|
16
|
+
// Java: SimpleReplaceRule#getWrongWords()
|
|
17
|
+
getWrongWords() {
|
|
18
|
+
if (wrongWords === null) wrongWords = AbstractSimpleReplaceRule.loadFromPath('/pl/replace.txt');
|
|
19
|
+
return wrongWords;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Java: SimpleReplaceRule(ResourceBundle,Language)
|
|
23
|
+
constructor(messages, language) {
|
|
24
|
+
super(messages, language);
|
|
25
|
+
SimpleReplaceRule.prototype.getWrongWords.call(this); // Java: static initializer runs at class load
|
|
26
|
+
this.setLocQualityIssueType(ITSIssueType.Misspelling);
|
|
27
|
+
this.setCategory(new Category(new CategoryId('PRAWDOPODOBNE_LITEROWKI'), 'Prawdopodobne literówki'));
|
|
28
|
+
this.setCheckLemmas(false);
|
|
29
|
+
this.addExamplePair(Example.wrong('Uspokój <marker>sei</marker>.'),
|
|
30
|
+
Example.fixed('Uspokój <marker>się</marker>.'));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Java: SimpleReplaceRule#getId()
|
|
34
|
+
getId() {
|
|
35
|
+
return SimpleReplaceRule.POLISH_SIMPLE_REPLACE_RULE;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Java: SimpleReplaceRule#getDescription()
|
|
39
|
+
getDescription() {
|
|
40
|
+
return 'Typowe literówki i niepoprawne wyrazy (domowi, sie, niewiadomo, duh, cie…)';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Java: SimpleReplaceRule#getShort()
|
|
44
|
+
getShort() {
|
|
45
|
+
return 'Literówka';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Java: SimpleReplaceRule#getMessage(String,List)
|
|
49
|
+
getMessage(tokenStr, replacements) {
|
|
50
|
+
return 'Wyraz „' + tokenStr + '” to najczęściej literówka; poprawnie pisze się: '
|
|
51
|
+
+ replacements.join(', ') + '.';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Java: SimpleReplaceRule#isCaseSensitive()
|
|
55
|
+
isCaseSensitive() {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Java: SimpleReplaceRule#getLocale()
|
|
60
|
+
getLocale() {
|
|
61
|
+
return PL_LOCALE;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Java: org.languagetool.rules.pl.WordCoherencyRule
|
|
2
|
+
import { AbstractWordCoherencyRule } from '@valueerror/ltjs-core/src/core/rules/AbstractWordCoherencyRule.js';
|
|
3
|
+
import { WordCoherencyDataLoader } from '@valueerror/ltjs-core/src/core/rules/WordCoherencyDataLoader.js';
|
|
4
|
+
import { Example } from '@valueerror/ltjs-core/src/core/rules/model/Examples.js';
|
|
5
|
+
|
|
6
|
+
let wordMap = null; // Java: static wordMap = new WordCoherencyDataLoader().loadWords("/pl/coherency.txt")
|
|
7
|
+
|
|
8
|
+
// Java: WordCoherencyRule (pl)
|
|
9
|
+
export class WordCoherencyRule extends AbstractWordCoherencyRule {
|
|
10
|
+
static FQCN = 'org.languagetool.rules.pl.WordCoherencyRule';
|
|
11
|
+
|
|
12
|
+
// Java: WordCoherencyRule(ResourceBundle)
|
|
13
|
+
constructor(messages) {
|
|
14
|
+
super(messages);
|
|
15
|
+
this.getWordMap(); // Java: static initializer runs at class load
|
|
16
|
+
this.addExamplePair(Example.wrong('Grapefruity są zdrowe. <marker>Grejpfrut</marker> smakuje najlepiej smażony.'),
|
|
17
|
+
Example.fixed('Grapefruity są zdrowe. <marker>Grapefruit</marker> smakuje najlepiej smażony.'));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Java: WordCoherencyRule#getWordMap()
|
|
21
|
+
getWordMap() {
|
|
22
|
+
if (wordMap === null) wordMap = new WordCoherencyDataLoader().loadWords('/pl/coherency.txt');
|
|
23
|
+
return wordMap;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Java: WordCoherencyRule#getMessage(String,String)
|
|
27
|
+
getMessage(word1, word2) {
|
|
28
|
+
return 'Formy „' + word1 + '” i „' + word2 + '” zwykle nie powinny być używane jednocześnie.';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Java: WordCoherencyRule#getId()
|
|
32
|
+
getId() {
|
|
33
|
+
return 'PL_WORD_COHERENCY';
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Java: WordCoherencyRule#getDescription()
|
|
37
|
+
getDescription() {
|
|
38
|
+
return 'Jednolita pisownia wyrazów o obocznej dopuszczalnej pisowni';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// Java: org.languagetool.synthesis.pl.PolishSynthesizer
|
|
2
|
+
import { DictionaryLookup } from '@valueerror/ltjs-core/src/lib/fsa/DictionaryLookup.js';
|
|
3
|
+
import { Pattern, PatternSyntaxException } from '@valueerror/ltjs-core/src/lib/java/regex/index.js';
|
|
4
|
+
import { JavaHashSet } from '@valueerror/ltjs-core/src/lib/java/collections/JavaHashSet.js';
|
|
5
|
+
import { javaSplit, javaReplace } from '@valueerror/ltjs-core/src/lib/java/strings.js';
|
|
6
|
+
import { NullPointerException } from '@valueerror/ltjs-core/src/lib/java/errors.js';
|
|
7
|
+
import { registerComponent, sharedComponent } from '@valueerror/ltjs-core/src/core/language/components.js';
|
|
8
|
+
import { BaseSynthesizer } from '@valueerror/ltjs-core/src/core/tagging/synthesis/BaseSynthesizer.js';
|
|
9
|
+
import { loadWords } from '@valueerror/ltjs-core/src/core/tagging/synthesis/SynthesizerTools.js';
|
|
10
|
+
import { getDataBroker } from '@valueerror/ltjs-core/src/core/resources/LtStatics.js';
|
|
11
|
+
|
|
12
|
+
const RESOURCE_FILENAME = '/pl/polish_synth.dict';
|
|
13
|
+
const TAGS_FILE_NAME = '/pl/polish_tags.txt';
|
|
14
|
+
|
|
15
|
+
const POTENTIAL_NEGATION_TAG = ':aff';
|
|
16
|
+
const NEGATION_TAG = ':neg';
|
|
17
|
+
const NEGATION_TAG_PATTERN = Pattern.compile(NEGATION_TAG);
|
|
18
|
+
const COMP_TAG = 'com';
|
|
19
|
+
const SUP_TAG = 'sup';
|
|
20
|
+
const PATTERN = Pattern.compile('.*[a-z]\\.[a-z].*');
|
|
21
|
+
const DOT = Pattern.compile('.', Pattern.LITERAL);
|
|
22
|
+
|
|
23
|
+
// Java: PolishSynthesizer
|
|
24
|
+
export class PolishSynthesizer extends BaseSynthesizer {
|
|
25
|
+
static FQCN = 'org.languagetool.synthesis.pl.PolishSynthesizer';
|
|
26
|
+
|
|
27
|
+
// Java: PolishSynthesizer#INSTANCE
|
|
28
|
+
static get INSTANCE() {
|
|
29
|
+
return sharedComponent(PolishSynthesizer.FQCN);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Java: PolishSynthesizer#PolishSynthesizer() (the deprecated (Language) constructor delegates here)
|
|
33
|
+
constructor() {
|
|
34
|
+
super(null, RESOURCE_FILENAME, TAGS_FILE_NAME, 'pl');
|
|
35
|
+
this.plPossibleTags = null; // Java: PolishSynthesizer#possibleTags (private field, separate from BaseSynthesizer's)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Java: PolishSynthesizer#synthesize(AnalyzedToken,String) / synthesize(AnalyzedToken,String,boolean) (overload by argument count)
|
|
39
|
+
synthesize(token, posTag, posTagRegExp) {
|
|
40
|
+
return posTagRegExp === undefined ? this.synthesize2(token, posTag) : this.synthesize3(token, posTag, posTagRegExp);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Java: PolishSynthesizer#synthesize(AnalyzedToken,String)
|
|
44
|
+
synthesize2(token, posTag) {
|
|
45
|
+
if (posTag === null || posTag === undefined) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
const synthesizer = new DictionaryLookup(this.getDictionary());
|
|
49
|
+
let isNegated = false;
|
|
50
|
+
if (token.getPOSTag() !== null) {
|
|
51
|
+
isNegated = posTag.indexOf(NEGATION_TAG) > 0
|
|
52
|
+
|| (token.getPOSTag().indexOf(NEGATION_TAG) > 0
|
|
53
|
+
&& !(posTag.indexOf(COMP_TAG) > 0) && !(posTag.indexOf(SUP_TAG) > 0));
|
|
54
|
+
}
|
|
55
|
+
if (posTag.indexOf('+') > 0) {
|
|
56
|
+
return this.synthesize3(token, posTag, true);
|
|
57
|
+
}
|
|
58
|
+
return this.getWordForms(token, posTag, isNegated, synthesizer);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Java: PolishSynthesizer#synthesize(AnalyzedToken,String,boolean)
|
|
62
|
+
synthesize3(token, pos, posTagRegExp) {
|
|
63
|
+
if (pos === null || pos === undefined) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
let posTag = pos;
|
|
67
|
+
if (posTagRegExp) {
|
|
68
|
+
if (this.plPossibleTags === null) {
|
|
69
|
+
this.plPossibleTags = loadWords(getDataBroker().getFromResourceDirAsStream(TAGS_FILE_NAME));
|
|
70
|
+
}
|
|
71
|
+
const synthesizer = new DictionaryLookup(this.getDictionary());
|
|
72
|
+
let results = [];
|
|
73
|
+
|
|
74
|
+
let isNegated = false;
|
|
75
|
+
if (token.getPOSTag() !== null) {
|
|
76
|
+
isNegated = posTag.indexOf(NEGATION_TAG) > 0
|
|
77
|
+
|| (token.getPOSTag().indexOf(NEGATION_TAG) > 0
|
|
78
|
+
&& !(posTag.indexOf(COMP_TAG) > 0)
|
|
79
|
+
&& !(posTag.indexOf(SUP_TAG) > 0));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (isNegated) {
|
|
83
|
+
posTag = javaReplace(posTag, NEGATION_TAG, POTENTIAL_NEGATION_TAG + '?');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const p = Pattern.compile(javaReplace(posTag, '+', '|'));
|
|
88
|
+
for (const tag of this.plPossibleTags) {
|
|
89
|
+
const m = p.matcher(tag);
|
|
90
|
+
if (m.matches()) {
|
|
91
|
+
const wordForms = this.getWordForms(token, tag, isNegated, synthesizer);
|
|
92
|
+
if (wordForms !== null) {
|
|
93
|
+
results.push(...wordForms);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
} catch (e) {
|
|
98
|
+
if (!(e instanceof PatternSyntaxException)) throw e;
|
|
99
|
+
// Java: e.printStackTrace() (rare invalid regexp, issue 1651); results so far are kept
|
|
100
|
+
}
|
|
101
|
+
// remove duplicates (HashSet iteration order)
|
|
102
|
+
results = [...new JavaHashSet(results)];
|
|
103
|
+
return results;
|
|
104
|
+
}
|
|
105
|
+
return this.synthesize2(token, posTag);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Java: PolishSynthesizer#getPosTagCorrection(String)
|
|
109
|
+
getPosTagCorrection(posTag) {
|
|
110
|
+
if (posTag === null || posTag === undefined) throw new NullPointerException('Cannot invoke "String.contains(java.lang.CharSequence)" because "posTag" is null');
|
|
111
|
+
if (posTag.includes('.')) {
|
|
112
|
+
const tags = javaSplit(posTag, ':');
|
|
113
|
+
let pos = -1;
|
|
114
|
+
for (let i = 0; i < tags.length; i++) {
|
|
115
|
+
if (PATTERN.matcher(tags[i]).matches()) {
|
|
116
|
+
tags[i] = '(.*' + DOT.matcher(tags[i]).replaceAll('.*|.*') + '.*)';
|
|
117
|
+
pos = i;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (pos === -1) {
|
|
121
|
+
return posTag;
|
|
122
|
+
}
|
|
123
|
+
return tags.join(':');
|
|
124
|
+
}
|
|
125
|
+
return posTag;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Java: PolishSynthesizer#getWordForms(AnalyzedToken,String,boolean,IStemmer)
|
|
129
|
+
getWordForms(token, posTag, isNegated, synthesizer) {
|
|
130
|
+
const forms = [];
|
|
131
|
+
if (isNegated) {
|
|
132
|
+
const wordForms = synthesizer.lookup(token.getLemma() + '|'
|
|
133
|
+
+ NEGATION_TAG_PATTERN.matcher(posTag).replaceFirst(POTENTIAL_NEGATION_TAG));
|
|
134
|
+
if (wordForms !== null) {
|
|
135
|
+
for (const wd of wordForms) {
|
|
136
|
+
forms.push('nie' + wd.getStem());
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
const wordForms = synthesizer.lookup(token.getLemma() + '|' + posTag);
|
|
141
|
+
for (const wd of wordForms) {
|
|
142
|
+
if (wd.getStem() !== null) {
|
|
143
|
+
forms.push(String(wd.getStem()));
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return forms;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
registerComponent(PolishSynthesizer.FQCN, () => new PolishSynthesizer());
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Java: org.languagetool.tagging.disambiguation.pl.PolishHybridDisambiguator
|
|
2
|
+
import { registerComponent } from '@valueerror/ltjs-core/src/core/language/components.js';
|
|
3
|
+
import { AbstractDisambiguator } from '@valueerror/ltjs-core/src/core/tagging/disambiguation/AbstractDisambiguator.js';
|
|
4
|
+
import { MultiWordChunker } from '@valueerror/ltjs-core/src/core/tagging/disambiguation/MultiWordChunker.js';
|
|
5
|
+
import { XmlRuleDisambiguator } from '@valueerror/ltjs-core/src/core/disambiguation/XmlRuleDisambiguator.js';
|
|
6
|
+
import { Polish } from '../language/Polish.js';
|
|
7
|
+
|
|
8
|
+
// Java: PolishHybridDisambiguator
|
|
9
|
+
export class PolishHybridDisambiguator extends AbstractDisambiguator {
|
|
10
|
+
static FQCN = 'org.languagetool.tagging.disambiguation.pl.PolishHybridDisambiguator';
|
|
11
|
+
|
|
12
|
+
// Java: PolishHybridDisambiguator#PolishHybridDisambiguator() (field initialisers: chunker, then a second Polish instance)
|
|
13
|
+
constructor() {
|
|
14
|
+
super();
|
|
15
|
+
this.chunker = MultiWordChunker.getInstance('/pl/multiwords.txt');
|
|
16
|
+
this.disambiguator = new XmlRuleDisambiguator(new Polish());
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Java: PolishHybridDisambiguator#disambiguate(AnalyzedSentence)
|
|
20
|
+
disambiguate(input, checkCanceled = null) {
|
|
21
|
+
return this.chunker.disambiguate(this.disambiguator.disambiguate(input, checkCanceled), checkCanceled);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
registerComponent(PolishHybridDisambiguator.FQCN, () => new PolishHybridDisambiguator());
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// Java: org.languagetool.tagging.pl.PolishTagger
|
|
2
|
+
import { Locale } from '@valueerror/ltjs-core/src/lib/java/Locale.js';
|
|
3
|
+
import { Pattern } from '@valueerror/ltjs-core/src/lib/java/regex/index.js';
|
|
4
|
+
import { javaSplit, toLowerCase } from '@valueerror/ltjs-core/src/lib/java/strings.js';
|
|
5
|
+
import { registerComponent } from '@valueerror/ltjs-core/src/core/language/components.js';
|
|
6
|
+
import { AnalyzedToken } from '@valueerror/ltjs-core/src/core/AnalyzedToken.js';
|
|
7
|
+
import { AnalyzedTokenReadings } from '@valueerror/ltjs-core/src/core/AnalyzedTokenReadings.js';
|
|
8
|
+
import { BaseTagger } from '@valueerror/ltjs-core/src/core/tagging/BaseTagger.js';
|
|
9
|
+
import { CachingWordListLoader } from '@valueerror/ltjs-core/src/core/rules/spelling/CachingWordListLoader.js';
|
|
10
|
+
import { asString, isMixedCase, uppercaseFirstChar } from '@valueerror/ltjs-core/src/core/text/StringTools.js';
|
|
11
|
+
|
|
12
|
+
const NEGATION_PREFIX = 'nie';
|
|
13
|
+
const COMPAR_SUPERL = Pattern.compile('(adv|adj:.+):(com|sup)'); // Java: PolishTagger#COMPAR_SUPERL
|
|
14
|
+
const MIN_NEGATED_LENGTH = NEGATION_PREFIX.length + 4;
|
|
15
|
+
const NEGATION_EXCEPTIONS_FILE = '/pl/nie_compar_exceptions.txt';
|
|
16
|
+
|
|
17
|
+
// Java: PolishTagger
|
|
18
|
+
export class PolishTagger extends BaseTagger {
|
|
19
|
+
static FQCN = 'org.languagetool.tagging.pl.PolishTagger';
|
|
20
|
+
|
|
21
|
+
// Java: PolishTagger#PolishTagger()
|
|
22
|
+
constructor() {
|
|
23
|
+
super('/pl/polish.dict', new Locale('pl'));
|
|
24
|
+
this.negationExceptions = new Set(new CachingWordListLoader().loadWords(NEGATION_EXCEPTIONS_FILE));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Java: PolishTagger#tag(List)
|
|
28
|
+
tag(sentenceTokens) {
|
|
29
|
+
const tokenReadings = [];
|
|
30
|
+
let pos = 0;
|
|
31
|
+
for (const word of sentenceTokens) {
|
|
32
|
+
const l = [];
|
|
33
|
+
const lowerWord = toLowerCase(word, this.locale);
|
|
34
|
+
const taggerTokens = this.asAnalyzedTokenListForTaggedWords(word, this.getWordTagger().tag(word));
|
|
35
|
+
const isLowercase = word === lowerWord;
|
|
36
|
+
// normal case
|
|
37
|
+
this.plAddTokens(taggerTokens, l);
|
|
38
|
+
if (!isLowercase) {
|
|
39
|
+
// lowercase
|
|
40
|
+
const lowerTaggerTokens = this.asAnalyzedTokenListForTaggedWords(word, this.getWordTagger().tag(lowerWord));
|
|
41
|
+
this.plAddTokens(lowerTaggerTokens, l);
|
|
42
|
+
}
|
|
43
|
+
// uppercase
|
|
44
|
+
if (l.length === 0 && isLowercase) {
|
|
45
|
+
const upperTaggerTokens = this.asAnalyzedTokenListForTaggedWords(word, this.getWordTagger().tag(uppercaseFirstChar(word)));
|
|
46
|
+
this.plAddTokens(upperTaggerTokens, l);
|
|
47
|
+
}
|
|
48
|
+
// additional language-dependent tagging, e.g. joined "nie"
|
|
49
|
+
if (l.length === 0) {
|
|
50
|
+
this.plAddTokens(this.additionalTags(word, this.getWordTagger()), l);
|
|
51
|
+
}
|
|
52
|
+
if (l.length === 0) {
|
|
53
|
+
l.push(new AnalyzedToken(word, null, null));
|
|
54
|
+
}
|
|
55
|
+
tokenReadings.push(new AnalyzedTokenReadings(l, pos));
|
|
56
|
+
pos += word.length;
|
|
57
|
+
}
|
|
58
|
+
return tokenReadings;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Java: PolishTagger#additionalTags(String,WordTagger)
|
|
62
|
+
additionalTags(word, wordTagger) {
|
|
63
|
+
const lowerWord = toLowerCase(word, this.locale);
|
|
64
|
+
if (lowerWord.length < MIN_NEGATED_LENGTH
|
|
65
|
+
|| !lowerWord.startsWith(NEGATION_PREFIX)
|
|
66
|
+
|| isMixedCase(word)
|
|
67
|
+
|| this.negationExceptions.has(lowerWord)) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
// Only one lookup, so "nienielepiej" stays untagged.
|
|
71
|
+
const base = lowerWord.substring(NEGATION_PREFIX.length);
|
|
72
|
+
const result = [];
|
|
73
|
+
for (const baseToken of this.asAnalyzedTokenListForTaggedWords(word, wordTagger.tag(base))) {
|
|
74
|
+
const posTag = baseToken.getPOSTag();
|
|
75
|
+
if (posTag !== null && baseToken.getLemma() !== null && COMPAR_SUPERL.matcher(posTag).matches()) {
|
|
76
|
+
result.push(new AnalyzedToken(word, posTag, NEGATION_PREFIX + baseToken.getLemma()));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return result.length === 0 ? null : result;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Java: PolishTagger#addTokens(List,List) (private; renamed so BaseTagger#addTokens keeps its behaviour)
|
|
83
|
+
plAddTokens(taggedTokens, l) {
|
|
84
|
+
if (taggedTokens !== null) {
|
|
85
|
+
for (const at of taggedTokens) {
|
|
86
|
+
const tagsArr = javaSplit(asString(at.getPOSTag()), '\\+');
|
|
87
|
+
for (const currTag of tagsArr) {
|
|
88
|
+
l.push(new AnalyzedToken(at.getToken(), currTag, at.getLemma()));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
registerComponent(PolishTagger.FQCN, () => new PolishTagger());
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// Java: org.languagetool.tokenizers.pl.PolishWordTokenizer
|
|
2
|
+
import { StringTokenizer } from '@valueerror/ltjs-core/src/lib/java/StringTokenizer.js';
|
|
3
|
+
import { isDigit } from '@valueerror/ltjs-core/src/lib/java/Character.js';
|
|
4
|
+
import { javaSplit } from '@valueerror/ltjs-core/src/lib/java/strings.js';
|
|
5
|
+
import { IOException, RuntimeException } from '@valueerror/ltjs-core/src/lib/java/errors.js';
|
|
6
|
+
import { registerComponent } from '@valueerror/ltjs-core/src/core/language/components.js';
|
|
7
|
+
import { WordTokenizer } from '@valueerror/ltjs-core/src/core/text/tokenizers/WordTokenizer.js';
|
|
8
|
+
|
|
9
|
+
// Polish prefixes that should never be used to split parts of words
|
|
10
|
+
const prefixes = new Set([
|
|
11
|
+
'arcy', 'neo', 'pre', 'anty', 'eks', 'bez', 'beze', 'ekstra', 'hiper', 'infra', 'kontr', 'maksi', 'midi', 'między',
|
|
12
|
+
'mini', 'nad', 'nade', 'około', 'ponad', 'post', 'pro', 'przeciw', 'pseudo', 'super', 'śród', 'ultra', 'wice', 'wokół', 'wokoło',
|
|
13
|
+
]);
|
|
14
|
+
|
|
15
|
+
// Java: PolishWordTokenizer
|
|
16
|
+
export class PolishWordTokenizer extends WordTokenizer {
|
|
17
|
+
static FQCN = 'org.languagetool.tokenizers.pl.PolishWordTokenizer';
|
|
18
|
+
|
|
19
|
+
// Java: PolishWordTokenizer#PolishWordTokenizer()
|
|
20
|
+
constructor() {
|
|
21
|
+
super();
|
|
22
|
+
this.tagger = null;
|
|
23
|
+
this.plTokenizing = `${super.getTokenizingCharacters()}–‚`; // n-dash
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Java: PolishWordTokenizer#tokenize(String)
|
|
27
|
+
tokenize(text) {
|
|
28
|
+
const l = [];
|
|
29
|
+
const st = new StringTokenizer(text, this.plTokenizing, true);
|
|
30
|
+
while (st.hasMoreElements()) {
|
|
31
|
+
const token = st.nextToken();
|
|
32
|
+
if (token.length > 1) {
|
|
33
|
+
if (token.endsWith('-')) {
|
|
34
|
+
l.push(token.substring(0, token.length - 1));
|
|
35
|
+
l.push('-');
|
|
36
|
+
} else if (token.charAt(0) === '-') {
|
|
37
|
+
l.push('-');
|
|
38
|
+
l.push(...this.tokenize(token.substring(1)));
|
|
39
|
+
} else if (token.includes('-')) {
|
|
40
|
+
const tokenParts = javaSplit(token, '-');
|
|
41
|
+
if (prefixes.has(tokenParts[0]) || this.tagger === null) {
|
|
42
|
+
l.push(token);
|
|
43
|
+
} else if (isDigit(tokenParts[tokenParts.length - 1].charCodeAt(0))) {
|
|
44
|
+
// split numbers at dash or minus sign, 1-10
|
|
45
|
+
for (let i = 0; i < tokenParts.length; i++) {
|
|
46
|
+
l.push(tokenParts[i]);
|
|
47
|
+
if (i !== tokenParts.length - 1) {
|
|
48
|
+
l.push('-');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
} else {
|
|
52
|
+
const testedTokens = [...tokenParts, token];
|
|
53
|
+
try {
|
|
54
|
+
const taggedToks = this.tagger.tag(testedTokens);
|
|
55
|
+
if (taggedToks.length === tokenParts.length + 1 && !taggedToks[tokenParts.length].isTagged()) {
|
|
56
|
+
let isCompound = false;
|
|
57
|
+
switch (tokenParts.length) {
|
|
58
|
+
case 2:
|
|
59
|
+
if ((taggedToks[0].hasPosTag('adja') // "niemiecko-indonezyjski"
|
|
60
|
+
&& taggedToks[1].hasPartialPosTag('adj:'))
|
|
61
|
+
|| (taggedToks[0].hasPartialPosTag('subst:') // "kobieta-wojownik"
|
|
62
|
+
&& taggedToks[1].hasPartialPosTag('subst:'))
|
|
63
|
+
|| (taggedToks[0].hasPartialPosTag('num:') // osiemnaście-dwadzieścia
|
|
64
|
+
&& taggedToks[1].hasPartialPosTag('num:'))) {
|
|
65
|
+
isCompound = true;
|
|
66
|
+
}
|
|
67
|
+
break;
|
|
68
|
+
case 3:
|
|
69
|
+
if (taggedToks[0].hasPosTag('adja')
|
|
70
|
+
&& taggedToks[1].hasPosTag('adja')
|
|
71
|
+
&& taggedToks[2].hasPartialPosTag('adj:')) {
|
|
72
|
+
isCompound = true;
|
|
73
|
+
}
|
|
74
|
+
break;
|
|
75
|
+
default:
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
if (isCompound) {
|
|
79
|
+
for (let i = 0; i < tokenParts.length; i++) {
|
|
80
|
+
l.push(tokenParts[i]);
|
|
81
|
+
if (i !== tokenParts.length - 1) {
|
|
82
|
+
l.push('-');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
l.push(token);
|
|
87
|
+
}
|
|
88
|
+
} else {
|
|
89
|
+
l.push(token);
|
|
90
|
+
}
|
|
91
|
+
} catch (e) {
|
|
92
|
+
if (e instanceof IOException) throw new RuntimeException(e);
|
|
93
|
+
throw e;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
l.push(token);
|
|
98
|
+
}
|
|
99
|
+
} else {
|
|
100
|
+
l.push(token);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return this.joinEMailsAndUrls(l);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Java: PolishWordTokenizer#setTagger(Tagger)
|
|
107
|
+
setTagger(tagger) {
|
|
108
|
+
this.tagger = tagger;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
registerComponent(PolishWordTokenizer.FQCN, () => new PolishWordTokenizer());
|