【问题标题】:Efficiently Compare Successive Characters in String有效地比较字符串中的连续字符
【发布时间】:2013-03-20 12:16:09
【问题描述】:

我正在做一些文本分析,需要在String 中记录字符转换的频率。我有 n 个字符类别:例如,isUpperCase()isNumber()isSpace()

鉴于有 n 个类别,将有 n^2 个类别的转换,例如“isUpperCase()-->isUpperCase()”、“isUpperCase-->isLetter()”、“isLetter()-->isUpperCase()”等

给定一个文本块,我想记录发生的转换次数。我会想象构造一个Map,其转换类型为KeysInteger 为每个Value

对于文本块“TO”,Map 看起来像 [isUpper -> isUpper : 1, isUpper -> isSpace : 1]

不过,我无法弄清楚的部分是如何构造一个 Map,据我所知,Key 将包含 2 个 boolean 方法。

【问题讨论】:

    标签: java text map nlp


    【解决方案1】:

    创建一个表示字符类型的enum - 您需要一种方法来获取给定字符的字符类型enum。我确信有比我在下面所做的更好的方法来做到这一点,但这留给读者作为练习。

    接下来创建一个方法,获取先前和当前字符并将它们的类型连接成唯一的String

    最后循环遍历输入字符串,嘿嘿。

    private static enum CharacterType {
    
        UPPER {
            @Override
            boolean isA(final char c) {
                return Character.isUpperCase(c);
            }
        },
        LOWER {
            @Override
            boolean isA(final char c) {
                return Character.isLowerCase(c);
            }
        },
        SPACE {
            @Override
            boolean isA(final char c) {
                return Character.isWhitespace(c);
            }
        },
        UNKOWN {
            @Override
            boolean isA(char c) {
                return false;
            }
        };
    
        abstract boolean isA(final char c);
    
        public static CharacterType toType(final char c) {
            for (CharacterType type : values()) {
                if (type.isA(c)) {
                    return type;
                }
            }
            return UNKOWN;
        }
    }
    
    private static String getTransitionType(final CharacterType prev, final CharacterType current) {
        return prev + "_TO_" + current;
    }
    
    public static void main(String[] args) {
        final String myString = "AAaaA Aaa  AA";
        final Map<String, Integer> countMap = new TreeMap<String, Integer>() {
            @Override
            public Integer put(final String key, final Integer value) {
                final Integer currentCount = get(key);
                if (currentCount == null) {
                    return super.put(key, value);
                }
                return super.put(key, currentCount + value);
            }
        };
        final char[] myStringAsArray = myString.toCharArray();
        CharacterType prev = CharacterType.toType(myStringAsArray[0]);
        for (int i = 1; i < myStringAsArray.length; ++i) {
            final CharacterType current = CharacterType.toType(myStringAsArray[i]);
            countMap.put(getTransitionType(prev, current), 1);
            prev = current;
        }
        for (final Entry<String, Integer> entry : countMap.entrySet()) {
            System.out.println(entry);
        }
    }
    

    输出:

    LOWER_TO_LOWER=2
    LOWER_TO_SPACE=1
    LOWER_TO_UPPER=1
    SPACE_TO_SPACE=1
    SPACE_TO_UPPER=2
    UPPER_TO_LOWER=2
    UPPER_TO_SPACE=1
    UPPER_TO_UPPER=2
    

    对问题内容(825 个字符)运行该方法需要 9 毫秒。

    【讨论】:

    • 首先,我只想说声谢谢。我不知道这是否可行,因为我需要了解更多关于 enum 的信息,但它看起来很棒!
    • 这确实是一个非常优雅的解决方案。我喜欢!
    【解决方案2】:

    如果您认为大多数转换都会出现,那么二维数组效果最好:

    int n = _categories.size();
    int[][] _transitionFreq = new int[n][n];
    

    如果你认为它是一个解析数组,那么映射在内存使用方面会更有效,但在性能方面效率会更低。

    您必须根据您的数据和字符类型的数量做出权衡。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-11
      • 1970-01-01
      相关资源
      最近更新 更多