Java 有效地比较字符串中的连续字符

Java 有效地比较字符串中的连续字符,java,text,map,nlp,Java,Text,Map,Nlp,我正在做一些文本分析,需要在字符串中记录字符转换的频率。我有n类字符:例如,isUpperCase(),isNumber(),和isSpace() 假设有n个类别,则将有n^2个类别的转换,例如“isUpperCase()-->isUpperCase()”、“isUpperCase-->isLetter()”、“isUpperCase()”等 给定一个文本块,我想记录发生的转换次数。我可以想象构建一个映射,其中转换类型作为键,而整数作为每个值 对于文本块“TO”,Map看起来像[isUpper-

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

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

给定一个文本块,我想记录发生的转换次数。我可以想象构建一个
映射
,其中转换类型作为
,而
整数
作为每个

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


然而,我无法理解的部分是如何构造一个
映射
,据我所见,
将由2个
布尔
方法组成。

创建一个表示字符类型的
枚举
,您需要一种方法来获取给定字符的字符类型
枚举
。我相信有比我在下面做的更好的方法,但这是留给读者的练习

接下来,创建一个方法,该方法接受上一个字符和当前字符,并将它们的类型连接到一个唯一的
字符串中

最后,在输入字符串上循环,然后返回

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

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

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

接下来,创建一个方法,该方法接受上一个字符和当前字符,并将它们的类型连接到一个唯一的
字符串中

最后,在输入字符串上循环,然后返回

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

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

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

int n = _categories.size();
int[][] _transitionFreq = new int[n][n];
如果您认为它将是一个解析数组,那么映射在内存使用方面将更有效,但在性能方面效率更低


这是您必须根据数据和字符类型数量进行的权衡

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

int n = _categories.size();
int[][] _transitionFreq = new int[n][n];
如果您认为它将是一个解析数组,那么映射在内存使用方面将更有效,但在性能方面效率更低


这是您必须根据数据和字符类型数量进行的权衡

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