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

时间:2013-03-20 12:16:09

标签: java text map nlp

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

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

给定一个文本块,我想记录发生的转换次数。我想可以构建一个Map,其转换类型为KeysIntegerValue

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

但我无法弄清楚的部分是如何构建Map,从我所看到的情况来看,Key将包含2个boolean方法。

2 个答案:

答案 0 :(得分:4)

创建一个代表字符类型的enum - 您需要一种方法来获得给定字符的字符类型enum。我确信有更好的方法可以做到这一点,而不是我在下面所做的,但这是留给读者的练习。

接下来创建一个方法,该方法接收先前和当前字符并将其类型连接成唯一的String

最后循环输入字符串并嘿presto。

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毫秒。

答案 1 :(得分:0)

如果您认为大多数过渡都会出现,那么二维数组最有效:

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

如果您认为它将是一个解析数组,那么地图在内存使用方面将更有效,但在性能方面效率较低。

根据您的数据和字符类型的数量,这是您需要做出的权衡。