@@ -71,6 +71,7 @@ detect(PyObject *self, PyObject *args, PyObject *kwArgs) {
7171 int flagVerbose = 0 ;
7272 int flagQuiet = 0 ;
7373 int flagEcho = 0 ;
74+ int flagBestEffort = 0 ;
7475
7576 static const char *kwList[] = {" utf8Bytes" ,
7677 " isPlainText" ,
@@ -103,9 +104,15 @@ detect(PyObject *self, PyObject *args, PyObject *kwArgs) {
103104 /* Echo every input buffer to stderr. */
104105 " debugEcho" ,
105106
107+ /* If true, allow low-quality results for short text,
108+ rather than forcing the result to UNKNOWN_LANGUAGE. This may be of use for
109+ those desiring approximate results on short input text, but there is no claim
110+ that these results ave very good. make a guess at the language even if quality is low (text is short) */
111+ " bestEffort" ,
112+
106113 NULL };
107114
108- if (!PyArg_ParseTupleAndKeywords (args, kwArgs, " s#|izzzziiiiiii " ,
115+ if (!PyArg_ParseTupleAndKeywords (args, kwArgs, " s#|izzzziiiiiiii " ,
109116 (char **) kwList,
110117 &bytes, &numBytes,
111118 &isPlainText,
@@ -119,7 +126,8 @@ detect(PyObject *self, PyObject *args, PyObject *kwArgs) {
119126 &flagCR,
120127 &flagVerbose,
121128 &flagQuiet,
122- &flagEcho)) {
129+ &flagEcho,
130+ &flagBestEffort)) {
123131 return 0 ;
124132 }
125133
@@ -142,6 +150,9 @@ detect(PyObject *self, PyObject *args, PyObject *kwArgs) {
142150 if (flagEcho != 0 ) {
143151 flags |= CLD2 ::kCLDFlagEcho ;
144152 }
153+ if (flagBestEffort != 0 ) {
154+ flags |= CLD2 ::kCLDFlagBestEffort ;
155+ }
145156
146157 PyObject *CLDError = GETSTATE (self)->error ;
147158
@@ -172,21 +183,28 @@ detect(PyObject *self, PyObject *args, PyObject *kwArgs) {
172183 int percent3[3 ];
173184 double normalized_score3[3 ];
174185 int textBytesFound;
186+ int validPrefixBytes;
175187 CLD2 ::ResultChunkVector resultChunkVector;
176188
177189 Py_BEGIN_ALLOW_THREADS
178- CLD2::ExtDetectLanguageSummary (bytes, numBytes,
179- isPlainText != 0 ,
180- &cldHints,
181- flags,
182- language3,
183- percent3,
184- normalized_score3,
185- returnVectors != 0 ? &resultChunkVector : 0 ,
186- &textBytesFound,
187- &isReliable);
190+ CLD2::ExtDetectLanguageSummaryCheckUTF8 (bytes, numBytes,
191+ isPlainText != 0 ,
192+ &cldHints,
193+ flags,
194+ language3,
195+ percent3,
196+ normalized_score3,
197+ returnVectors != 0 ? &resultChunkVector : 0 ,
198+ &textBytesFound,
199+ &isReliable,
200+ &validPrefixBytes);
188201 Py_END_ALLOW_THREADS
189202
203+ if (validPrefixBytes < numBytes) {
204+ PyErr_Format (CLDError, " input contains invalid UTF-8 around byte %d (of %d)" , validPrefixBytes, numBytes);
205+ return 0 ;
206+ }
207+
190208 PyObject *details = PyTuple_New (3 );
191209 for (int idx=0 ;idx<3 ;idx++) {
192210 CLD2 ::Language lang = language3[idx];
@@ -223,6 +241,7 @@ detect(PyObject *self, PyObject *args, PyObject *kwArgs) {
223241 textBytesFound,
224242 details);
225243 }
244+
226245 Py_DECREF (details);
227246 return result;
228247}
@@ -231,22 +250,23 @@ const char *DOC =
231250 " Detect language(s) from a UTF8 string.\n\n "
232251
233252 " Arguments:\n\n "
234- " utf8Bytes: text to detect, encoded as UTF-8 bytes (required)\n\n "
253+ " utf8Bytes: The text to detect, encoded as UTF-8 bytes (required). If\n "
254+ " this is not valid UTF-8, then an cld2.error is raised.\n\n "
235255
236- " isPlainText: if False, then the input is HTML and CLD will skip HTML tags,\n "
256+ " isPlainText: If False, then the input is HTML and CLD will skip HTML tags,\n "
237257 " expand HTML entities, detect HTML <lang ...> tags, etc.\n\n "
238258
239- " hintTopLevelDomain: e .g., 'id' boosts Indonesian\n\n "
259+ " hintTopLevelDomain: E .g., 'id' boosts Indonesian\n\n "
240260
241- " hintLanguage: e .g., 'ITALIAN' or 'it' boosts Italian; see cld.LANGUAGES\n "
261+ " hintLanguage: E .g., 'ITALIAN' or 'it' boosts Italian; see cld.LANGUAGES\n "
242262 " for all known language\n\n "
243263
244- " hintLanguageHTTPHeaders: e .g., 'mi,en' boosts Maori and English\n\n "
264+ " hintLanguageHTTPHeaders: E .g., 'mi,en' boosts Maori and English\n\n "
245265
246- " hintEncoding: e .g, 'SJS' boosts Japanese; see cld.ENCODINGS for all known\n "
266+ " hintEncoding: E .g, 'SJS' boosts Japanese; see cld.ENCODINGS for all known\n "
247267 " encodings\n\n "
248268
249- " returnVectors: if True then the vectors indicating which language was\n "
269+ " returnVectors: If True then the vectors indicating which language was\n "
250270 " detected in which byte range are returned in addition to\n "
251271 " details. The vectors are a sequence of (bytesOffset,\n "
252272 " bytesLength, languageName, languageCode), in order.\n "
@@ -265,6 +285,12 @@ const char *DOC =
265285 " text chunks and their detected languages. See\n "
266286 " docs/InterpretingCLD2UnitTestOutput.pdf to interpret this output.\n\n "
267287
288+ " bestEffort: If True then allow low-quality results for short text,\n "
289+ " rather than forcing the result to UNKNOWN_LANGUAGE. This\n "
290+ " may be of use for those desiring approximate results on\n "
291+ " short input text, but there is no claim that these result\n "
292+ " are very good.\n\n "
293+
268294 " debugCR: In that HTML file, force a new line for each chunk.\n\n "
269295
270296 " debugVerbose: In that HTML file, show every lookup entry.\n\n "
@@ -320,21 +346,33 @@ static struct PyModuleDef moduledef = {
320346
321347// PyObject *
322348PyMODINIT_FUNC
323- PyInit__pycld2 (void )
349+ #ifdef CLD2_FULL
350+ PyInit_cld2full (void )
351+ #else
352+ PyInit_cld2 (void )
353+ #endif
324354
325355#else // IS_PY3K
326356
327357#define INITERROR return
328358
329359PyMODINIT_FUNC
330- init_pycld2 ()
360+ #ifdef CLD2_FULL
361+ initcld2full ()
362+ #else
363+ initcld2 ()
364+ #endif
331365#endif
332366{
333367
334368#ifdef IS_PY3K
335369 PyObject *m = PyModule_Create (&moduledef);
336370#else
337- PyObject* m = Py_InitModule (" _pycld2" , CLDMethods);
371+ #ifdef CLD2_FULL
372+ PyObject* m = Py_InitModule (" cld2full" , CLDMethods);
373+ #else
374+ PyObject* m = Py_InitModule (" cld2" , CLDMethods);
375+ #endif
338376#endif
339377
340378 if (m == NULL ) {
@@ -343,7 +381,12 @@ init_pycld2()
343381
344382 struct PYCLDState *st = GETSTATE (m);
345383
346- st->error = PyErr_NewException ((char *) " cld.error" , NULL , NULL );
384+ #ifdef CLD2_FULL
385+ st->error = PyErr_NewException ((char *) " cld2full.error" , NULL , NULL );
386+ #else
387+ st->error = PyErr_NewException ((char *) " cld2.error" , NULL , NULL );
388+ #endif
389+
347390 if (st->error == NULL ) {
348391 Py_DECREF (m);
349392 INITERROR ;
@@ -410,6 +453,7 @@ init_pycld2()
410453
411454 upto = 0 ;
412455
456+ #ifdef CLD2_FULL
413457 PyObject* detLangs = PyTuple_New (165 );
414458
415459 PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" ABKHAZIAN" ));
@@ -577,7 +621,108 @@ init_pycld2()
577621 PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" YORUBA" ));
578622 PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" ZHUANG" ));
579623 PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" ZULU" ));
624+ #else
625+ PyObject* detLangs = PyTuple_New (94 );
580626
627+ // List originally sent by Dick Sites on 7/17/2013, then I
628+ // added 6 new languages from the Jan 2014 release, and
629+ // removed 5 and added 13 langs from the Oct 2014 release:
630+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" AFRIKAANS" ));
631+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" ALBANIAN" ));
632+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" ARABIC" ));
633+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" ARMENIAN" ));
634+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" AZERBAIJANI" ));
635+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" BASQUE" ));
636+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" BELARUSIAN" ));
637+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" BENGALI" ));
638+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" BIHARI" ));
639+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" BOSNIAN" ));
640+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" BULGARIAN" ));
641+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" BURMESE" ));
642+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" CATALAN" ));
643+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" CEBUANO" ));
644+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" CHEROKEE" ));
645+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" CROATIAN" ));
646+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" CZECH" ));
647+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" Chinese" ));
648+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" ChineseT" ));
649+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" DANISH" ));
650+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" DHIVEHI" ));
651+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" DUTCH" ));
652+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" ENGLISH" ));
653+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" ESTONIAN" ));
654+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" FINNISH" ));
655+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" FRENCH" ));
656+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" GALICIAN" ));
657+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" GANDA" ));
658+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" GEORGIAN" ));
659+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" GERMAN" ));
660+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" GREEK" ));
661+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" GUJARATI" ));
662+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" HAITIAN_CREOLE" ));
663+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" HEBREW" ));
664+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" HINDI" ));
665+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" HMONG" ));
666+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" HUNGARIAN" ));
667+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" ICELANDIC" ));
668+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" INDONESIAN" ));
669+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" INUKTITUT" ));
670+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" IRISH" ));
671+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" ITALIAN" ));
672+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" JAVANESE" ));
673+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" Japanese" ));
674+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" KANNADA" ));
675+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" KAZAKH" ));
676+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" KHMER" ));
677+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" KINYARWANDA" ));
678+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" KURDISH" ));
679+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" KYRGYZ" ));
680+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" Korean" ));
681+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" LAOTHIAN" ));
682+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" LATVIAN" ));
683+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" LIMBU" ));
684+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" LITHUANIAN" ));
685+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" MACEDONIAN" ));
686+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" MALAGASY" ));
687+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" MALAY" ));
688+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" MALAYALAM" ));
689+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" MALTESE" ));
690+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" MARATHI" ));
691+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" NEPALI" ));
692+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" NORWEGIAN" ));
693+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" NYANJA" ));
694+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" ORIYA" ));
695+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" PERSIAN" ));
696+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" POLISH" ));
697+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" PORTUGUESE" ));
698+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" PUNJABI" ));
699+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" ROMANIAN" ));
700+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" RUSSIAN" ));
701+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" SCOTS_GAELIC" ));
702+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" SERBIAN" ));
703+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" SESOTHO" ));
704+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" SINHALESE" ));
705+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" SLOVAK" ));
706+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" SLOVENIAN" ));
707+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" SPANISH" ));
708+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" SUNDANESE" ));
709+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" SWAHILI" ));
710+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" SWEDISH" ));
711+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" SYRIAC" ));
712+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" TAGALOG" ));
713+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" TAJIK" ));
714+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" TAMIL" ));
715+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" TELUGU" ));
716+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" THAI" ));
717+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" TURKISH" ));
718+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" UKRAINIAN" ));
719+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" URDU" ));
720+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" UZBEK" ));
721+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" VIETNAMESE" ));
722+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" WELSH" ));
723+ PyTuple_SET_ITEM (detLangs, upto++, PyUnicode_FromString (" YIDDISH" ));
724+ #endif
725+
581726 // Steals ref:
582727 PyModule_AddObject (m, " DETECTED_LANGUAGES" , detLangs);
583728
0 commit comments