ispellaff2myspell 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. #!/usr/bin/perl -w
  2. # -*- coding: iso-8859-1 -*-
  3. # $Id: ispellaff2myspell,v 1.29 2005/07/04 12:21:55 agmartin Exp $
  4. #
  5. # (C) 2002-2005 Agustin Martin Domingo <agustin.martin@hispalinux.es>
  6. #
  7. # This program is free software; you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation; either version 2 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with this program; if not, write to the Free Software
  19. # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. sub usage {
  21. print "ispellaff2myspell: A program to convert ispell affix tables to myspell format
  22. (C) 2002-2005 Agustin Martin Domingo <agustin.martin\@hispalinux.es> License: GPL
  23. Usage:
  24. ispellaff2myspell [options] <affixfile>
  25. Options:
  26. --affixfile=s Affix file
  27. --bylocale Use current locale setup for upper/lowercase
  28. conversion
  29. --charset=s Use specified charset for upper/lowercase
  30. conversion (defaults to latin1)
  31. --debug Print debugging info
  32. --extraflags Allow some non alphabetic flags
  33. --lowercase=s Lowercase string
  34. --myheader=s Header file
  35. --printcomments Print commented lines in output
  36. --replacements=s Replacements file
  37. --split=i Split flags with more that i entries
  38. --uppercase=s Uppercase string
  39. --wordlist=s Still unused
  40. Currently allowed valued for charset are: latin1, latin2, latin3
  41. This script does not create the dict file. Something like
  42. ( echo `cat mydict.words+ | wc -l`; cat mydict.words+ ) > mydict.dict
  43. should do the work, with mydict.words+ being the ispell munched wordlist
  44. ";
  45. exit;
  46. }
  47. sub debugprint {
  48. if ( $debug ){
  49. print STDERR "@_";
  50. }
  51. }
  52. sub shipoutflag{
  53. my $flag_entries=scalar @flag_array;
  54. if ( $flag_entries != 0 ){
  55. if ( $split ){
  56. while ( @flag_array ){
  57. my @flag_subarray=splice(@flag_array,0,$split);
  58. my $subflag_entries=scalar @flag_subarray;
  59. if ( scalar @flag_array ){
  60. print "$myaffix $flagname $flagcombine $subflag_entries S\n";
  61. } else {
  62. print "$myaffix $flagname $flagcombine $subflag_entries\n";
  63. }
  64. print join("\n",@flag_subarray);
  65. print "\n\n";
  66. }
  67. } else {
  68. print "$myaffix $flagname $flagcombine $flag_entries\n";
  69. print join("\n",@flag_array);
  70. print "\n\n";
  71. }
  72. }
  73. @flag_array=();
  74. $flagname='';
  75. $flagcombine='';
  76. }
  77. sub mylc{
  78. my $inputstring=shift;
  79. my $outputstring;
  80. if ( $bylocale ){
  81. {
  82. use locale;
  83. $outputstring = lc $inputstring;
  84. }
  85. } else {
  86. if ( $charset eq "latin0" ){
  87. $lowercase='a-z';
  88. $uppercase='A-Z޼';
  89. } elsif ( $charset eq "latin1" ){
  90. $lowercase='a-z';
  91. $uppercase='A-Z';
  92. } elsif ( $charset eq "latin2" ){
  93. $lowercase='a-z';
  94. $uppercase='A-Z';
  95. } elsif ( $charset eq "latin3" ){
  96. $lowercase='a-z';
  97. $uppercase='A-Z';
  98. # } elsif ( $charset eq "other_charset" ){
  99. # die "latin2 still unimplemented";
  100. } else {
  101. if ( not $lowercase and not $uppercase ){
  102. die "Unsupported charset [$charset]
  103. use explicitely --lowercase=string and --uppercase=string
  104. options. Remember that both string must match exactly, but
  105. case changed.
  106. ";
  107. }
  108. }
  109. $outputstring=$inputstring;
  110. eval "\$outputstring=~tr/$uppercase/$lowercase/";
  111. }
  112. return $outputstring;
  113. }
  114. sub validate_flag (){
  115. my $flag = shift;
  116. if ($flag=~m/[a-zA-Z]+/){
  117. return $flag;
  118. } elsif ( $hasextraflags ){
  119. foreach ( keys %theextraflags ){
  120. if ($flag =~ m/^$_/){
  121. $flag =~ s/^$_//;
  122. return $flag;
  123. }
  124. }
  125. }
  126. return '';
  127. }
  128. sub process_replacements{
  129. my $file = shift;
  130. my @replaces = ();
  131. open (REPLACE,"< $file") ||
  132. die "Error: Could not open replacements file: $file\n";
  133. while (<REPLACE>){
  134. next unless m/^REP[\s\t]*\D.*/;
  135. next if m/^REP\s+[0-9]+/;
  136. s/\015\012//;
  137. s/\015//;
  138. chomp;
  139. push @replaces, $_;
  140. }
  141. close REPLACE;
  142. my $number = scalar @replaces;
  143. print "REP $number\n";
  144. foreach ( @replaces ){
  145. print $_ . "\n";
  146. }
  147. }
  148. # -----------------------------------------------------------
  149. # Now the progran start, after the functions are defined
  150. # -----------------------------------------------------------
  151. use Getopt::Long;
  152. # Initializing option values
  153. $affixfile = '';
  154. $bylocale = '';
  155. $charset = '';
  156. $debug = '';
  157. $lowercase = '';
  158. $myheader = '';
  159. $printcomments = '';
  160. $replacements = '';
  161. $split = '';
  162. $uppercase = '';
  163. $wordlist = '';
  164. $hasextraflags = '';
  165. @flag_array = ();
  166. %theextraflags = ();
  167. # Initializing root values
  168. $rootremove = "0";
  169. $rootname = '';
  170. $addtoroot = '';
  171. $comment = '';
  172. # Initializing flag values
  173. $flagname = '';
  174. $flagcombine = '';
  175. $inflags = '';
  176. GetOptions ('affixfile=s' => \$affixfile,
  177. 'bylocale' => \$bylocale,
  178. 'charset=s' => \$charset,
  179. 'debug' => \$debug,
  180. 'extraflags:s' => sub {
  181. $hasextraflags = 1;
  182. shift;
  183. $theflag = shift;
  184. $theextraflags{$theflag}++ if $theflag},
  185. 'lowercase=s' => \$lowercase,
  186. 'myheader=s' => \$myheader,
  187. 'printcomments' => \$printcomments,
  188. 'replacements=s'=> \$replacements,
  189. 'split=i' => \$split,
  190. 'uppercase=s' => \$uppercase,
  191. 'wordlist=s' => \$wordlist) or usage;
  192. if ( not $affixfile ){
  193. $affixfile=shift or usage;
  194. }
  195. if ( $charset and ( $lowercase or $uppercase )){
  196. die "Error: charset and lowercase/uppercase options
  197. are incompatible. Use either charset or lowercase/uppercase options to
  198. specify the patterns
  199. "
  200. } elsif ( not $lowercase and not $uppercase and not $charset ){
  201. $charset="latin1";
  202. }
  203. if ( scalar(keys %theextraflags) == 0 && $hasextraflags ){
  204. $theextraflags{"\\\\"}++;
  205. }
  206. debugprint "$affixfile $charset";
  207. open (AFFIXFILE,"< $affixfile") ||
  208. die "Error: Could not open affix file: $affixfile";
  209. if ( $myheader ){
  210. my $myspell_header=`cat $myheader`;
  211. print $myspell_header . "\n";
  212. }
  213. while (<AFFIXFILE>){
  214. chomp;
  215. if (/^\s*\#.*/){
  216. debugprint "Ignoring line $.\n";
  217. print "$_\n" if $printcomments;
  218. } elsif (/^\s*$/){
  219. debugprint "Ignoring line $.\n";
  220. } elsif (/^\s*prefixes/){
  221. debugprint "Prefixes starting in line $.\n";
  222. $affix="PFX";
  223. } elsif (/^\s*suffixes/){
  224. debugprint "Suffixes starting in line $.\n";
  225. $affix="SFX";
  226. } elsif (/^[\s\t]*flag.*/){
  227. next if not $affix; # In case we are still in the preamble
  228. shipoutflag if $inflags;
  229. $inflags="yes";
  230. s/^[\s\t]*flag[\s\t]*//;
  231. s/[\s\t]*:.*$//;
  232. debugprint "Found flag $_ in line $.\n";
  233. if (/\*/){
  234. s/[\*\s]//g;
  235. $flagcombine="Y";
  236. debugprint "Flag renamed to $_ with combine=$flagcombine\n";
  237. } else {
  238. $flagcombine="N";
  239. }
  240. if ( $flagname = &validate_flag($_) ){
  241. $myaffix = $affix;
  242. } else {
  243. $myaffix = "\# $affix";
  244. $flagname = $_;
  245. print STDERR "Ignoring invalid flag $flagname in line $.\n";
  246. }
  247. } elsif ( $affix and $inflags ) {
  248. ($rootname,@comments) = split('#',$_);
  249. $comment = '# ' . join('#',@comments);
  250. $rootname =~ s/\s*//g;
  251. $rootname = mylc $rootname;
  252. ($rootname,$addtoroot) = split('>',$rootname);
  253. if ( $addtoroot =~ s/^\-//g ){
  254. ($rootremove,$addtoroot) = split(',',$addtoroot);
  255. $addtoroot = "0" unless $addtoroot;
  256. $addtoroot = "0" if ( $addtoroot eq "-");
  257. } else {
  258. $rootremove = "0";
  259. }
  260. $addtoroot =~ s/\\\-/\-/g; # prefix ANTI\- to anti-
  261. if ( $rootname eq '.' && $rootremove ne "0" ){
  262. $rootname = $rootremove;
  263. }
  264. debugprint "$rootname, $addtoroot, $rootremove\n";
  265. if ( $printcomments ){
  266. $affix_line=sprintf("%s %s %-5s %-11s %-24s %s",
  267. $myaffix, $flagname, $rootremove,
  268. $addtoroot, $rootname, $comment);
  269. } else {
  270. $affix_line=sprintf("%s %s %-5s %-11s %s",
  271. $myaffix, $flagname, $rootremove,
  272. $addtoroot, $rootname);
  273. }
  274. $rootremove = "0";
  275. $rootname = '';
  276. $addtoroot = '';
  277. $comment = '';
  278. @comments = ();
  279. push @flag_array,$affix_line;
  280. debugprint "$affix_line\n";
  281. } else {
  282. #
  283. }
  284. }
  285. shipoutflag;
  286. close AFFIXFILE;
  287. if ( $replacements ){
  288. &process_replacements($replacements);
  289. }
  290. __END__
  291. =head1 NAME
  292. B<ispellaff2myspell> - A program to convert ispell affix tables to myspell format.
  293. =head1 SYNOPSIS
  294. ispellaff2myspell [options] <affixfile> --myheader your_header
  295. Options:
  296. --affixfile=s Affix file
  297. --bylocale Use current locale setup for upper/lowercase
  298. conversion
  299. --charset=s Use specified charset for upper/lowercase
  300. conversion (defaults to latin1)
  301. --debug Print debugging info
  302. --extraflags=s Allow some non alphabetic flags
  303. --lowercase=s Lowercase string
  304. --myheader=s Header file
  305. --printcomments Print commented lines in output
  306. --replacements=s Replacements file
  307. --split=i Split flags with more that i entries
  308. --uppercase=s Uppercase string
  309. =head1 DESCRIPTION
  310. B<ispellaff2myspell> is a script that will convert ispell affix tables
  311. to myspell format in a more or less successful way.
  312. This script does not create the dict file. Something like
  313. ( echo `cat mydict.words+ | wc -l`; cat mydict.words+ ) > mydict.dict
  314. should do the work, with mydict.words+ being the munched wordlist
  315. =head1 OPTIONS
  316. =over 8
  317. =item B<--affixfile=s>
  318. Affix file. You can put it directly in the command line.
  319. =item B<--bylocale>
  320. Use current locale setup for upper/lowercase conversion. Make sure
  321. that the selected locale match the dictionary one, or you might get
  322. into trouble.
  323. =item B<--charset=s>
  324. Use specified charset for upper/lowercase conversion (defaults to latin1).
  325. Currently allowed values for charset are: latin0, latin1, latin2, latin3.
  326. =item B<--debug>
  327. Print some debugging info.
  328. =item B<--extraflags:s>
  329. Allows some non alphabetic flags.
  330. When invoked with no value the supported flags are currently those
  331. corresponding to chars represented with the escape char B<\> as
  332. first char. B<\> will be stripped.
  333. When given with the flag prefix will allow that flag and strip the
  334. given prefix. Be careful when giving the prefix to properly escape chars,
  335. e.g. you will need B<-e "\\\\"> or B<-e '\\'> for flags like B<\[> to be stripped to
  336. B<[>. Otherwise you might even get errors. Use B<-e "^"> to allow all
  337. flags and pass them unmodified.
  338. You will need a call to -e for each flag type, e.g.,
  339. B<-e "\\\\" -e "~\\\\"> (or B<-e '\\' -e '~\\'>).
  340. When a prefix is explicitely set, the default value (anything starting by B<\>)
  341. is disabled and you need to enable it explicitely as in previous example.
  342. =item B<--lowercase=s>
  343. Lowercase string. Manually set the string of lowercase chars. This
  344. requires B<--uppercase> having exactly that string but uppercase.
  345. =item B<--myheader=s>
  346. Header file. The myspell aff header. You need to write it
  347. manually. This can contain everything you want to be before the affix table
  348. =item B<--printcomments>
  349. Print commented lines in output.
  350. =item B<--replacements=file>
  351. Add a pre-defined replacements table taken from 'file' to the .aff file.
  352. Will skip lines not beginning with REP, and set the replacements number
  353. appropriately.
  354. =item B<--split=i>
  355. Split flags with more that i entries. This can be of interest for flags
  356. having a lot of entries. Will split the flag in chunks containing B<i>
  357. entries.
  358. =item B<--uppercase=s>
  359. Uppercase string. Manually set the sring of uppercase chars. This
  360. requires B<--lowercase> having exactly that string but lowercase.
  361. =back
  362. If your encoding is currently unsupported you can send me a file with
  363. the two strings of lower and uppercase chars. Note that they must match
  364. exactly but case changed. It will look something like
  365. $lowercase='a-z';
  366. $uppercase='A-Z';
  367. =head1 SEE ALSO
  368. The OpenOffice.org Lingucomponent Project home page
  369. L<http://lingucomponent.openoffice.org/index.html>
  370. and the document
  371. L<http://lingucomponent.openoffice.org/affix.readme>
  372. that provides information about the basics of the myspell affix file format.
  373. You can also take a look at
  374. /usr/share/doc/libmyspell-dev/affix.readme.gz
  375. /usr/share/doc/libmyspell-dev/README.compoundwords
  376. /usr/share/doc/libmyspell-dev/README.replacetable
  377. in your Debian system.
  378. =head1 AUTHORS
  379. Agustin Martin <agustin.martin@hispalinux.es>
  380. =cut