【问题标题】:Efficient encoding all the special characters in a string into entities将字符串中的所有特殊字符高效编码为实体
【发布时间】:2016-07-05 07:41:06
【问题描述】:

我有一个像这样的字符串“abcd !@&$%^^&*()!/”。我有一个单独字符串中字符的所有实体代码的列表,即只编码另一个字符串中的那些字符“!=&4 ....^ = 9 ...”。我想通过正则表达式将所有特殊字符转换为它们的实体,除了字母数字,因为对字符使用循环太慢了。

例如它应该显示“abc ..;..”,换句话说,将键盘上的所有特殊字符转换成单词。

我可以写一个有效的正则表达式吗?我已经用循环尝试过这个,但是一个一个地查看每个字符并维护其他字符串中所有特殊字符实体的列表太慢了

有库,但它们不会转换所有字符。

我写的代码

// String to be encoded

String sDecoded = "abcd !@#$%^&*();'m,";
// Special character entity list to put instead to special character. It is     tokenized on cross and divide symbol as it cannot be entered by user on keyboard

String specialCharacters = "&÷$amp;×–÷–"


// Check the input
if (sDecoded == null || sDecoded.trim ().length () == 0)
  return (sDecoded);

// Use StringTokenizer which is faster than split method
StringTokenizer st = new StringTokenizer(specialCharacters, "×");
String[] reg = null;
String[] charactersArray = sDecoded.split("");
String sEncoded = "";

// now loop on it and in each iteration, we will be getting a decodedCharacter:EncodedEntity pair 


for(int i = 0; i < charactersArray.length; i++)
{   
    st = new StringTokenizer(specialCharacters, "×");


    while(st.hasMoreElements())
    {
        reg = st.nextElement().toString().split("÷");

         // This is an error, the character should not be blank ever because it will be character that we will encode
         if(StringUtils.isBlank(reg[0]))
            return sDecoded;

        String c = charactersArray[i];


        if(c.equalsIgnoreCase(reg[0]))
        {
            sEncoded = sEncoded + c.replace(reg[0], reg[1]);
            break;
        }

        if(st.countTokens() == 0)
            sEncoded = sEncoded + c.toString();

 }

}

    return (sEncoded);

【问题讨论】:

  • 如果逐个字符执行此操作很慢,则使用正则表达式会更慢。正则表达式不是魔法棒——当它们不匹配时它会扫描字符串和回溯。如何准确地展示您的尝试,我们也许可以帮助您改进它。
  • 您粘贴的代码无法编译 - 字符串文字有问题。
  • 为什么要使用复杂的specialCharacters 字符串?为什么不使用正确的Map,这样搜索起来会更快?
  • 其实我不会用String来装。这只是一个例子。这些字符将保存在配置文件中的代码之外,我们可以在不更改代码的情况下进行更改。因此,无论我们要添加什么字符,我们都以标记化字符串的方式添加到该 .ini 文件中并从那里读取。
  • 太好了,我正在询问它将在 Java 程序中采用的形式。毕竟,您不会考虑在程序中一次又一次地读取ini 文件——您将一次将其加载到数据结构中。该数据结构不应是您创建的复杂字符串,而是一个映射。

标签: java regex xml


【解决方案1】:

我不知道您使用的“高效”的定义是什么,但是使用简单调用 Apache commons-text StringEscapeUtils 实用程序类有“不要重新发明轮子”的效率:

String encoded = StringEscapeUtils.escapeXml11(str);

String encoded = StringEscapeUtils.escapeHtml4(str);

以及各种其他类似的方法,具体取决于您想要的确切编码。


注意:该类最初位于 commons-lang3 库中,但已被弃用并移至 commons-text 库。

【讨论】:

  • 它不会像 !@#$%^^&*()_ 那样转换每个字符 -
  • 我们可以使用正则表达式吗?
  • @aiden 没有。正则表达式匹配,它不会转换。我或许能够提供一种有效的算法,但请准确告诉我您希望如何完成编码,例如对您指定的&amp;#4..; 进行编码'!'。这真的是你想要的吗?如果没有,你到底想要什么? '!' 是十进制 33,你想要八进制 041
  • 非常感谢您的回复。我只是把 ... 因为堆栈跟踪删除了任何特殊实体。所以,实际上我想将 & 转换为 &和 , 到 , 和 ' 到 '。原因是当使用这些特殊字符时,我的 XSLT 转换器会删除它们,例如如果在字符串“abcd - def”中使用 Dash,则输出为“”。所以,唯一的办法就是对特殊字符进行编码。
  • @3xCh1_23 链接从 common-lang3 更新为 common-text。谢谢。
【解决方案2】:

您的方法非常缓慢且效率低下。也许现在将正则表达式用作所有事情的灵丹妙药看起来很优雅,但绝对不适合这项任务。我看到你也在使用标记器,它也很慢。循环内的循环也会降低性能。

我建议使用字符串生成器的迭代方式,这将产生极快的结果,您将自己尝试。为每个特殊字符做一个“if”语句。即使看起来代码太多,它也会非常快。测试自己。 试试这个:

class Scratch {

    public static void main(String[] args) {
        System.out.println(escapeSpecials("abc &"));
    }

    public static String escapeSpecials(String origin) {
        StringBuilder result = new StringBuilder();
        char[] chars = origin.toCharArray();
        for (char c : chars) {
            if (c == '&') {
                result.append("&amp;");
            } else if (c == '\u2013') {
                result.append("&ndash;");
            } else {
                // not a special character
                result.append(c);
            }
        }
        return result.toString();
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-02
    • 2017-07-05
    • 1970-01-01
    • 2013-09-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多