java - 使用 for 循环将文本中的书面数字转换为总和

标签 java

大家好,我正在完成一个在线练习,我必须创建一个读取多个文本段落的程序。所有数字(以文本形式写入)必须相加,总和显示在最后。

我有几个问题,如果你们不介意回答的话,因为我对此进行了很多研究。

这只是所使用文本的示例:

例如,请记住,您正站在十二点钟的平台上,并且有 五列火车每小时在九条轨道上运行。火车最快可以行驶两百英里 一小时。数百万亿之一...

我正在使用 StringTokenizer,因此每个单词都是单独读取的。

通过研究,我学会了创建代表每个单词的数组(请参阅代码示例),这样单词就可以轻松地表示为整数。虽然我也为每个数字创建了变量,但这可能不是必需的,尽管我不明白Java如何将一个单词表示为它的有效数字。 (再次请参阅代码)。

虽然我最大的问题是如何使用循环组合诸如 2081 = 281 这样的单词。

任何建议将不胜感激,我知道这段代码远非完美,因为我正在继续通过在线 Material 和书籍学习。

class wordsToNumberAdder

{
    public static void main()
{   

    String str = "Just remember that you're standing on a platform at twelve o'clock and there are 
    five trains that run every hour on nine tracks. A train can go as fast as two hundred miles
    an hour. One of millions of billions... ";

    StringTokenizer st = new StringTokenizer(str);


String[] digits = {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};
String[] tens = {"twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"};
String[] teens = {"ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"};
String[] power = {"hundred","thousand","million","billion"};

int one = 1, two = 2, three = 3, four = 4, five = 5, six = 6, seven = 7, eight = 8, nine = 9;
int twenty = 20, thirty = 30, forty = 40, fifty = 50, sixty = 60, seventy = 70, eighty = 80, ninety = 90;
int ten = 10, eleven = 11, twelve = 12, thirteen = 13, forteen = 14, fifthteen = 15, sixteen = 16;
int eighteen = 18, nineteen = 19, thirty = 30, hundred = 100, thousand = 1000; 
long billion = 1000000000;

double result = 0;
double group = 0;

while (set.hasMoreTokens()) {
        String word = set.nextToken();

for (int x = 0; x < power.length; i += 3) {

            if (word.equals(power[i])) {
            group = group * Math.pow(10, i);
            result = result + group;
            group = 0;
        }
    }

最佳答案

对我来说,这里有两个子问题:将输入解析为数字短语的集合(“2004”等),并将这些数字短语转换为实际值进行求和。

没有理由不使用映射来进行单词到值的解析。因此,不要尝试所有这些字段,而是尝试一下:

private static final Map<String, Long> NUMBER_MAP;
static {
  final Map<String, Long> map = new HashMap<String, Long>();
  map.put("one", 1L);
  map.put("two", 2L);
  map.put("three", 3L);
  ...
  map.put("hundred", 100L);
  map.put("hundreds", 100L);
  ...
  map.put("billion", 1000000000L);
  map.put("billions", 1000000000L);
  NUMBER_MAP = Collections.unmodifiableMap(map);
}

关于此的一些事情:首先,它是不可变的,因此这些映射都不能更改,并且最好尽量减少代码中的可变性。我还添加了几个单词的复数形式以方便解析。可能有一种更优雅的方式来处理这些复数,但我保持简单。我也拥有渴望简单的一切。

现在,进行解析。使用 StringTokenizer 是一个好的开始,但是您并没有用它做太多事情。这是我实现解析的方法:

public static void main(final String[] args) {
  final StringTokenizer tokenizer = new StringTokenizer(paragraph.replace(".", " ").toLowerCase());
  final StringBuilder phrase = new StringBuilder();
  final Set<String> numberSet = NUMBER_MAP.keySet();

  while (tokenizer.hasMoreTokens()) {
    final String token = tokenizer.nextToken();

    if (numberSet.contains(token)) {
      if (phrase.length() > 0) {
        phrase.append(" ");
      }
      phrase.append(token);
    } else if (!IGNORED_WORDS.contains(token)) {
      processPhrase(phrase.toString());
      phrase.setLength(0);
    }
  }

  processPhrase(phrase.toString());
}

那么我在这里做了什么?首先,我正在清理输入字符串以处理句点和大写字母。这样我们就可以解析像“一百”这样的句子。然后我使用 StringBuilder 来有效地构建数字短语。如果下一个标记(单词)位于我们的数字的键集中(例如“十八”或“一百”),我会将其添加到当前短语中,如果它不是短语中的第一个单词,则前面加一个空格。 IGNORED_WORDS 是一个(不可变)集合,仅包含字符串“and”。例如,这让我们可以解析“一百一十”。

那么短语到数字的转换怎么样呢?您上面写的循环对我来说没有多大意义。什么是i?什么是x?这是什么错别字?我使用的一般方法是一次考虑两个单词。如果只有一个,那就很简单了,我们就完成了。但如果有两个,我们就必须考虑它们的顺序。以“九百”为例。由于第二个值 (100) 大于第一个值 (9),因此我们将它们相乘并将它们添加到总和中。如果之前计算的值大于当前的值,我们只需将它们相加。这样,解析“12200”看起来像:

12 < 1000 : current sum = 12 * 1000 = 12000
2 < 100 : current sum += 2 * 100 = 12000 + 200 = 12200

我没有测试太多,but you can see my implementation of it here .

附录

map 在任何编程语言中都非常酷。映射是一对一(双射)函数:Java 映射中的键是函数的域,键映射到的值是范围。您可以使用 map.keySet() 提取所有键的集合,并使用 map.values() 提取值(其中 map 是一个实例化 Map 变量)。更强大的功能如下:

for (Map.Entry<K, V> entry : map.entrySet()) { 
  // loop over all entries in the map 
}

这实际上是映射中每个映射的迭代器,您可以在每次迭代中获取键和值。

无论如何,如果我们有一个映射变量,然后执行map.keySet(),我们就会得到该映射中所有键的 Java Set。在这篇文章的实例中,这个集合将包括字符串“一”,“二”,...“十亿”。换句话说,如果我有一个语句“A 映射到 B”的集合,并请求 keySet,我将获得这些语句中的所有“A”。

因此,将 NUMBER_MAP 视为从英文数字(键)到数学数字(值)的映射。从段落中的英文数字开始,我想得到数学数字。为此,我将段落中的值与 map 中的键进行了比较。

关于java - 使用 for 循环将文本中的书面数字转换为总和,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17381391/

相关文章:

java - 在 Spring redis session 中保存对象时出现 ClassCastException

java - Java中的组合锁赋值

java小程序(绘制快乐或笑脸)

java - 我怎样才能轻松地在 Eclipse 中只看到新的警告?

java - 允许 App Timer 在屏幕锁定时运行

java - Hadoop 2.7.2 HA群集无法启动备用名称节点

java - 在 JSTL 中使用 varStatus 时,如何访问 list<class> 的字段?

Java ConcurrentHashMap 在性能方面优于 HashMap 吗?

java - ArrayList 是否有可能在单写多读系统中失败?

java - 如何在Drools中匹配成员对象?