【问题标题】:Java Regex match UTF-8 String (Without Copy)Java 正则表达式匹配 UTF-8 字符串(无副本)
【发布时间】:2020-02-20 03:55:01
【问题描述】:

我正在从 SocketChannel 加载大型 UTF-8 文本,并且需要提取一些值。使用 java.util.regex 进行模式匹配非常适合,但使用 CharBuffer cb = UTF_8.decode(buffer); 解码为 Java 的 UTF-16 会复制此缓冲区,使用双倍空间。

有没有办法在 UTF-8 中创建 CharBuffer“视图”,或者以其他方式与字符集进行模式匹配?

【问题讨论】:

  • 您的正则表达式是否包含 unicode?如果不是,您可以将测试视为 ASCII 并稍后将提取的片段重新解码为 UTF-8
  • 是的,正则表达式都是 ascii。能给我举个例子吗?假设 ByteBuffer b 是 UTF-8 "hello alexey",而 Pattern 是 Pattern.compile("hello (?.*)")

标签: java regex performance utf-8 character-encoding


【解决方案1】:

您可以创建轻量级的 CharSequence 包装 ByteBuffer,它可以在没有正确 UTF8 处理的情况下进行简单的字节到字符转换。

只要您的正则表达式仅是 Latin1 字符,它就会对“天真”转换的字符串起作用。

只有 reg ex 匹配的范围需要从 UTF8 正确解码。

下面的代码说明了这种方法。

import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.junit.Test;

import junit.framework.Assert;


public class RegExSnippet {

    private static Charset UTF8 = Charset.forName("UTF8");

    @Test
    public void testByteBufferRegEx() throws UnsupportedEncodingException {

        // this UTF8 byte encoding of test string
        byte[] bytes = ("lkfmd;wmf;qmfqv amwfqwmf;c "
        + "<tag>This is some non ASCII text 'кирилицеский текст'</tag>"
        + "kjnfdlwncdlka-lksnflanvf ").getBytes(UTF8);

        ByteBuffer bb = ByteBuffer.wrap(bytes);

        ByteSeqWrapper bsw = new ByteSeqWrapper(bb);

        // pattern should contain only LATIN1 characters
        Matcher m = Pattern.compile("<tag>(.*)</tag>").matcher(bsw);

        Assert.assertTrue(m.find());

        String body = m.group(1);

        // extracted part is properly decoded as UTF8
        Assert.assertEquals("This is some non ASCII text 'кирилицеский текст'", body);
    }

    public static class ByteSeqWrapper implements CharSequence {

        final ByteBuffer buffer;

        public ByteSeqWrapper(ByteBuffer buf) {
            this.buffer = buf;
        }

        @Override
        public int length() {
            return buffer.remaining();
        }

        @Override
        public char charAt(int index) {
            return (char) (0xFF & buffer.get(index));
        }

        @Override
        public CharSequence subSequence(int start, int end) {
            ByteBuffer bb = buffer.duplicate();
            bb.position(bb.position() + start);
            bb.limit(bb.position() + (end - start));
            return new ByteSeqWrapper(bb);
        }

        @Override
        public String toString() {
            // a little hack to apply proper encoding
            // to a parts extracted by matcher
            CharBuffer cb = UTF8.decode(buffer);
            return cb.toString();
        }
    }
}

【讨论】:

  • 伙计,这太棒了!能够使用正则表达式比手动逐字节查找要好得多。谢谢!
猜你喜欢
  • 2013-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-27
相关资源
最近更新 更多