【问题标题】:Translate words in a string using BufferedReader (Java)使用 BufferedReader (Java) 翻译字符串中的单词
【发布时间】:2015-06-07 06:16:19
【问题描述】:

我已经为此工作了几天,但我无法取得任何进展。我尝试过使用 Scanner 和 BufferedReader,但没有成功。

基本上,我有一个工作方法(shortenWord),它接受一个字符串并根据格式如下的文本文件缩短它:

hello,lo
any,ne
anyone,ne1
thanks,thx

它还考虑了标点符号,所以“你好?”变成“lo?”等等

我需要能够读取字符串并单独翻译每个单词,所以“你好?任何人都谢谢!”将变为“lo?ne ne1 thx!”,基本上使用我对字符串中每个单词已有的方法。我拥有的代码将翻译第一个单词,但对其余部分没有任何作用。我认为这与我的 BufferedReader 的工作方式有关。

import java.io.*;

public class Shortener {
    private FileReader in ;
    /*
     * Default constructor that will load a default abbreviations text file.
     */
    public Shortener() {
        try {
            in = new FileReader( "abbreviations.txt" );
        }       

        catch ( Exception e ) {
            System.out.println( e );
        }
    }

    public String shortenWord( String inWord ) {
        String punc = new String(",?.!;") ;
        char finalchar = inWord.charAt(inWord.length()-1) ;
        String outWord = new String() ;
        BufferedReader abrv = new BufferedReader(in) ;

            // ends in punctuation
            if (punc.indexOf(finalchar) != -1 ) {
                String sub = inWord.substring(0, inWord.length()-1) ;
                outWord = sub + finalchar ;


            try {
                String line;
                while ( (line = abrv.readLine()) != null ) {
                    String[] lineArray = line.split(",") ;
                        if ( line.contains(sub) ) {
                            outWord = lineArray[1] + finalchar ;
                            }
                        }
                    }

            catch (IOException e) {
                System.out.println(e) ;
                }
            }

            // no punctuation
            else {
                outWord = inWord ;

                try {
                String line;

                    while( (line = abrv.readLine()) != null) {
                        String[] lineArray = line.split(",") ;
                            if ( line.contains(inWord) ) {
                                outWord = lineArray[1] ;
                            }
                        }
                    }

                catch (IOException ioe) {
                   System.out.println(ioe) ; 
                }
            }

        return outWord;
    }

    public void shortenMessage( String inMessage ) {
         String[] messageArray = inMessage.split("\\s+") ;
         for (String word : messageArray) {
            System.out.println(shortenWord(word));
        }
    }
}

非常感谢任何帮助,甚至是朝着正确方向轻推。

编辑:我尝试在 shortWord 方法的末尾关闭 BufferedReader,但在第一个说 BufferedReader 已关闭之后,它只会导致我在字符串中的每个单词上都出现错误。

【问题讨论】:

  • 在一个不相关的旁注中:我想像这样的单词缩短器是任何英语老师的噩梦燃料。
  • 对于每个单词一次又一次地读取文件是没有意义的,而且你实际上并没有这样做,因为一旦你到达文件的末尾,如果你不重新打开它或倒带它,它将停留在文件的末尾。更好的逻辑是打开文件,读取一行,然后将替换应用到每一行。
  • 或阅读“翻译”到Map<String, String>。还有你到底为什么用String punc = new String(",?.!;") ;而不是String punc = ",?.!;";
  • 啊,好吧,我明白你在说什么。我试图以这种方式实现它,因为我认为使用 shortWord 方法来节省再次写出逻辑会更好。我现在要试试你的方法,然后会报告!编辑:我还是 Java 新手,有时我会犯像 String 这样的愚蠢错误,如果它们有效,我通常不会识别出足以改变它的“坏”代码。 (我现在已经修好了,谢谢!)
  • 我不明白为什么它不起作用,你有一个用于此目的的调试器。我只能说你赚的比现在要难得多。您对以标点符号结尾的单词重复exact 代码,而对于没有标点符号的单词重复。没有用。去掉你的标点符号,记住它们。必须根据您的任何“字典”检查没有标点符号的单词,并在必要时进行替换。然后添加之前删除的标点符号。

标签: java bufferedreader


【解决方案1】:

我认为您可以使用HashMap 获得更简单的解决方案。在创建Shortener 对象时,将所有缩写词读入映射中,一旦有单词就引用它。该词将是key 和缩写value。像这样:

public class Shortener {

    private FileReader in;
    //the map
    private HashMap<String, String> abbreviations;

    /*
     * Default constructor that will load a default abbreviations text file.
     */
    public Shortener() {
        //initialize the map
        this.abbreviations = new HashMap<>();
        try {
            in = new FileReader("abbreviations.txt" );
            BufferedReader abrv = new BufferedReader(in) ;
            String line;
            while ((line = abrv.readLine()) != null) {
                String [] abv = line.split(",");
                //If there is not two items in the file, the file is malformed
                if (abv.length != 2) {
                    throw new IllegalArgumentException("Malformed abbreviation file");
                }
                //populate the map with the word as key and abbreviation as value
                abbreviations.put(abv[0], abv[1]);
            }
        }       

        catch ( Exception e ) {
            System.out.println( e );
        }
    }

    public String shortenWord( String inWord ) {
        String punc = new String(",?.!;") ;
        char finalchar = inWord.charAt(inWord.length()-1) ;

        // ends in punctuation
        if (punc.indexOf(finalchar) != -1) {
            String sub = inWord.substring(0, inWord.length() - 1);

            //Reference map
            String abv = abbreviations.get(sub);
            if (abv == null)
                return inWord;
            return new StringBuilder(abv).append(finalchar).toString();
        }

        // no punctuation
        else {
            //Reference map
            String abv = abbreviations.get(inWord);
            if (abv == null)
                return inWord;
            return abv;
        }
    }

    public void shortenMessage( String inMessage ) {
         String[] messageArray = inMessage.split("\\s+") ;
         for (String word : messageArray) {
            System.out.println(shortenWord(word));
        }
    }

    public static void main (String [] args) {
        Shortener s = new Shortener();
        s.shortenMessage("hello? any anyone thanks!");
    }
}

输出:

lo?
ne
ne1
thx!

编辑:

从 atommans 的回答中,您基本上可以删除 shortenWord 方法,方法是像这样修改 shortenMessage 方法:

public void shortenMessage(String inMessage) {
     for (Entry<String, String> entry:this.abbreviations.entrySet()) 
         inMessage = inMessage.replaceAll(entry.getKey(), entry.getValue());

     System.out.println(inMessage);
}

【讨论】:

  • 哇!非常感谢,这是完美的。我以前从未使用过 HashMaps 但这绝对是我问题的最简单实现:)
  • 没问题,我建议您阅读一下它们。您会发现它们可以简化许多解决方案,但对某些解决方案也不是必需的。 docs.oracle.com/javase/7/docs/api/java/util/HashMap.html
  • 也看看Properties。这样你就不必自己解析文件了。
【解决方案2】:

所以我看了看这个。首先,如果您可以选择更改文本文件的格式,我会将其更改为这样的(或 XML):

 key1=value1
 key2=value2

通过这样做,您以后可以使用 java 的Properties.load(Reader)。这将消除对文件进行任何手动解析的需要。'

如果通过任何更改您无法更改格式,那么您必须自己解析它。下面的代码可以做到这一点,并将结果放入名为shortningRulesMap 中,以后可以使用。

private void parseInput(FileReader reader) {
    try (BufferedReader br = new BufferedReader(reader)) {
        String line;
        while ((line = br.readLine()) != null) {
            String[] lineComponents = line.split(",");
            this.shortningRules.put(lineComponents[0], lineComponents[1]);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

在实际缩短消息时,我可能会选择正则表达式方法,例如\\bKEY\\b,其中 key 是您想要缩短的单词。 \\b 是正则表达式中的锚点,表示 word boundery,这意味着它不会匹配空格或标点符号。 用于缩短的整个代码将变成这样:

public void shortenMessage(String message) {
    for (Entry<String, String> entry : shortningRules.entrySet()) {
        message = message.replaceAll("\\b" + entry.getKey() + "\\b", entry.getValue());
    }
    System.out.println(message); //This should probably be a return statement instead of a sysout.
}

将它们放在一起会给你一些this,这里我添加了一个main 用于测试目的。

【讨论】:

  • 我喜欢replaceAll,不仅可以有效缩短单词,还可以缩短代码:P +1 for properties
  • 我想实现这个,但我有不止一种翻译(例如其他语言)。我可以将文本文件更改为使用 key1=value1 而不是另一个分隔符。你能帮我写一下我的帖子吗? http://stackoverflow.com/q/40575394/1919069 谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-09-04
  • 1970-01-01
  • 2021-06-24
  • 2019-11-18
  • 2013-11-26
  • 1970-01-01
  • 2018-07-24
相关资源
最近更新 更多