2 * Portions Copyright 2001 Sun Microsystems, Inc.
3 * Portions Copyright 1999-2001 Language Technologies Institute,
4 * Carnegie Mellon University.
5 * All Rights Reserved. Use is subject to license terms.
7 * See the file "license.terms" for information on usage and
8 * redistribution of this file, and for a DISCLAIMER OF ALL
11 package com.sun.speech.freetts.en.us;
13 import java.io.BufferedReader;
14 import java.io.IOException;
15 import java.io.InputStream;
16 import java.io.InputStreamReader;
18 import java.util.StringTokenizer;
21 * Implements a finite state machine that checks if a given string
22 * is pronounceable. If it is pronounceable, the method
23 * <code>accept()</code> will return true.
25 public class PronounceableFSM {
27 private static final String VOCAB_SIZE = "VOCAB_SIZE";
28 private static final String NUM_OF_TRANSITIONS = "NUM_OF_TRANSITIONS";
29 private static final String TRANSITIONS = "TRANSITIONS";
33 * The vocabulary size.
35 protected int vocabularySize;
39 * The transitions of this FSM
41 protected int[] transitions;
45 * Whether we should scan the input string from the front.
47 protected boolean scanFromFront;
51 * Constructs a PronounceableFSM with information in the given URL.
53 * @param url the URL that contains the FSM specification
54 * @param scanFromFront indicates whether this FSM should scan the input
55 * string from the front, or from the back
57 public PronounceableFSM(URL url, boolean scanFromFront) throws IOException {
58 this.scanFromFront = scanFromFront;
59 InputStream is = url.openStream();
66 * Constructs a PronounceableFSM with the given attributes.
68 * @param vocabularySize the vocabulary size of the FSM
69 * @param transitions the transitions of the FSM
70 * @param scanFromFront indicates whether this FSM should scan the input
71 * string from the front, or from the back
73 public PronounceableFSM(int vocabularySize, int[] transitions,
74 boolean scanFromFront) {
75 this.vocabularySize = vocabularySize;
76 this.transitions = transitions;
77 this.scanFromFront = scanFromFront;
82 * Loads the ASCII specification of this FSM from the given InputStream.
84 * @param is the input stream to load from
86 * @throws IOException if an error occurs on input.
88 private void loadText(InputStream is) throws IOException {
89 BufferedReader reader = new BufferedReader(new InputStreamReader(is));
91 while ((line = reader.readLine()) != null) {
92 if (!line.startsWith("***")) {
93 if (line.startsWith(VOCAB_SIZE)) {
94 vocabularySize = parseLastInt(line);
95 } else if (line.startsWith(NUM_OF_TRANSITIONS)) {
96 int transitionsSize = parseLastInt(line);
97 transitions = new int[transitionsSize];
98 } else if (line.startsWith(TRANSITIONS)) {
99 StringTokenizer st = new StringTokenizer(line);
100 String transition = st.nextToken();
102 while (st.hasMoreTokens() && i < transitions.length) {
103 transition = st.nextToken().trim();
104 transitions[i++] = Integer.parseInt(transition);
114 * Returns the integer value of the last integer in the given string.
116 * @param line the line to parse the integer from
120 private int parseLastInt(String line) {
121 String lastInt = line.trim().substring(line.lastIndexOf(" "));
122 return Integer.parseInt(lastInt.trim());
127 * Causes this FSM to transition to the next state given
128 * the current state and input symbol.
130 * @param state the current state
131 * @param symbol the input symbol
133 private int transition(int state, int symbol) {
134 for (int i = state; i < transitions.length; i++) {
135 if ((transitions[i] % vocabularySize) == symbol) {
136 return (transitions[i] / vocabularySize);
144 * Checks to see if this finite state machine accepts the given
147 * @param inputString the input string to be tested
149 * @return true if this FSM accepts, false if it rejects
151 public boolean accept(String inputString) {
153 int state = transition(0, '#');
154 int leftEnd = inputString.length() - 1;
155 int start = (scanFromFront) ? 0 : leftEnd;
157 for (int i = start; 0 <= i && i <= leftEnd; ) {
158 char c = inputString.charAt(i);
159 if (c == 'n' || c == 'm') {
161 } else if ("aeiouy".indexOf(c) != -1) {
166 state = transition(state, symbol);
169 } else if (symbol == 'V') {