【问题标题】:Converting written numbers in text into a sum using for loops使用 for 循环将文本中的书面数字转换为总和
【发布时间】:2013-06-29 14:45:19
【问题描述】:

大家好,我正在完成一个在线练习,我必须创建一个程序来读取几段文本。所有数字(以文字书写)必须相加,并在末尾显示总和。

如果你们不介意回答,我有几个问题,因为我已经研究了很多。

这只是使用的文本示例:

例如,请记住,您在 12 点钟站在一个平台上,并且有 五辆火车,每小时一班,在九条轨道上运行。一列火车可以跑两百英里 一小时。数百万中的一员……

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

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

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

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

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;
        }
    }

【问题讨论】:

  • how to convert words to number? 的可能重复项
  • 对代码块使用一致且符合逻辑的缩进。代码的缩进是为了帮助人们理解程序流程。
  • 它必须是for 循环而不是while 循环?
  • @mwerschy:这个问题 - 与您引用的问题不同 - 是一个有效的问题,它本身就显示了一些努力。你为什么要用那个措辞不当的问题来结束它?

标签: java


【解决方案1】:

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

没有理由不使用映射来解析单词到值。所以不要使用所有这些字段,试试这个:

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

附录

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

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

这实际上是对map中每个映射的迭代器,每次迭代都可以得到key和value。

无论如何,如果我们有一个映射变量,然后转到map.keySet(),我们会得到一个包含该映射中所有键的 Java 集。在这篇文章的实例中,这个 Set 将包括字符串“one”、“two”、...“billions”。换句话说,如果我有一组语句“A 映射到 B”,并要求提供 keySet,我会得到这些语句中的所有 'A'。

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

【讨论】:

  • 非常感谢您花时间和精力向我解释这一点
  • - 映射对我来说是一个新领域,在我的职业生涯后期将成为一个宝贵的资源,因为我刚开始作为一名研究生开发人员并尝试尽可能多地学习。再次感谢您的时间和努力。
  • 你好,我已经拆开了你的例子,我现在唯一不确定的一点是:final Set numberSet = NUM​​BER_MAP.keySet();我曾尝试研究 .keySet 的作用,但请您用外行的方式向我解释一下吗?
  • 抱歉回复晚了。我已经扩展了我的答案。
猜你喜欢
  • 2021-02-11
  • 1970-01-01
  • 1970-01-01
  • 2012-10-13
  • 2015-12-03
  • 2021-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多