【问题标题】:escape character using indexOf()使用 indexOf() 转义字符
【发布时间】:2013-11-20 20:28:47
【问题描述】:

我正在逐行读取文件,并使用line.indexOf('"', 1)substring() 将其拆分为更小的字符串 但是这种方式不会检测" 之前是否为\,因此它不会对转义字符做出反应。我该如何解决?

(我不能只使用line.split('"'),因为"既位于子字符串的开头和结尾,也不会被其他字符分割,因为我的任务不允许这样做。)

整个阅读片段是:

while ((line = bufferedReader.readLine()) != null) {
        System.out.println(line);
        while(line.length()>0){
            if(line.charAt(0) == ',' || line.charAt(0) == ' '){
                line = line.substring(1);
            }
            else{
                if(line.indexOf(',') != -1){
                    if (line.charAt(0) == '"'){
                    pabaiga = line.indexOf("\"", 1);
                    zodis = line.substring(0, pabaiga+1);
                    line = line.substring(pabaiga+1);
                    duomenys.add(zodis);
                    }
                    else{
                        pabaiga = line.indexOf(',');
                        zodis = line.substring(0, pabaiga);
                        line = line.substring(pabaiga);
                        duomenys.add(zodis);
                    }
                }
                else{
                    zodis = line;
                    line = line.substring(line.length());
                    duomenys.add(zodis);
                }
            }
            for(String elem : duomenys){
            System.out.println(elem);
            }
duomenys.removeAll(duomenys);
        }

我不能只用 , 分隔符来分割,因为字符串中间可能有一个,在文本文件中使用 \, 不是一种选择。所以我被建议将一个 sting 元素确定为“文本”,但如果它在中间包含另一个“或\”,我当前的代码不起作用。

如果我的文本文件中的行是"start \"title\" end", 10, 20, "text"
字符串数组应该包含

  • [0]"start "title" end"
  • [1]10
  • [2]20
  • [3]"text"

【问题讨论】:

  • 请提供输入示例。我想你可以split,因为它需要一个正则表达式。
  • 使用正则表达式来解决您的问题。你可以定义一个正则表达式取反,它只在前面的字符不是反斜杠()时才匹配
  • 请 [edit] 你的问题,输入和预期输出的例子很少,因为现在你的问题对你想要达到的目标不是很清楚。
  • 你能用一个反斜杠来转义另一个吗?如果是这样,您实际上会想要查找前面有偶数个反斜杠的第一个双引号。请说明这是否是您需要的。
  • @DavidWallace 是的,我想找到第一个不带 \ 的双引号。

标签: java escaping character


【解决方案1】:

您可以先将令牌存储在动态大小组件中,例如List。要使用您的标记填充此类列表,您需要遍历句子中的每个字符,如果不是 , 在引号内,则将其添加到 tokenBuilder,但如果该逗号在引号外,则将 tokenBuilder 的当前值添加到您的令牌列表。这是示例代码。

String line = "\"start \\\"title\\\" end\", 10, 20, \"text\"";

List<String> tokens = new ArrayList<>();
StringBuilder tokenBuilder = new StringBuilder();

boolean insideQuote = false;
char ch, prev = ' ';

for (int i = 0; i < line.length(); i++) {
    ch = line.charAt(i);
    if (ch == '"' && prev != '\\') {// normal " (without \ before)
        insideQuote = !insideQuote; // starts or ends quotation
    }
    // commas that are outside quote or last character in line 
    // should invoke adding non-empty builder to list
    if (ch == ',' && !insideQuote || i == line.length() - 1) {
        if (tokenBuilder.length() > 0) {
            tokens.add(tokenBuilder.toString().trim());
            tokenBuilder.delete(0, tokenBuilder.capacity());
        }

    }
    // add every character to builder except \ that are inside
    // quotes and have " after it
    else if (!(ch == '\\' && i + 1 < line.length()
            && line.charAt(i + 1) == '"' && insideQuote)) {
        tokenBuilder.append(ch);
    }
    prev = ch;//in next loop previous character should be our current one
}

String[] array = tokens.toArray(new String[tokens.size()]);

for (String s : array)
    System.out.println(">" + s);

输出:

>"start "title" end"
>10
>20
>"text

【讨论】:

  • 问题在于哪里可以是字符串中间的逗号,如果它在双引号之间,它应该被视为字符串的一部分。
【解决方案2】:

你可以使用这个(在线示例http://ideone.com/TTtlZV):

import java.util.*;
import java.lang.*;
import java.io.*;

/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
    {
         boolean inQuoted = false;

        List<String> parts = new ArrayList<String>();
        String s = "\"start \\\"title\\\" end\", 10, 20, \"text\"";
        StringBuilder current = new StringBuilder();
        for( int i=0; i<s.length(); i++ ){
            char c = s.charAt(i);
            char cPrev = ( i == 0 ? (char)0 : s.charAt(i-1));

            if( c == '"' && cPrev != '\\' ){
                inQuoted = !inQuoted;
            }

            if( c == ',' && !inQuoted ){
                if( current.length() > 0 ){
                    parts.add(current.toString());
                    current = new StringBuilder();
                }
            }
            else {
                int length = current.length();
                if( length > 1 && c == '"' && current.charAt(length-1) == '\\' ){
                    current.deleteCharAt(length-1);
                }
                current.append(c);
            }
        }
        if( current.length() > 0 ){
            parts.add(current.toString());
        }

        System.out.println(parts);
    }
}

它不会处理双重转义。例如

\\"

如果我运行这个程序,输出是:

["开始\"标题\"结束", 10, 20, "文本"]

【讨论】:

    【解决方案3】:

    如果你想要最后一个索引,那么只需使用 lastindexof

    .lastindexOf("\"", 1)
    

    只需替换

    pabaiga = line.indexOf("\"", 1);
    

    pabaiga = line.lastindexOf("\"", 1);
    

    【讨论】:

    • OP 想要找到第一个" 前面没有 `\` 的索引。 IE。第一个 未转义 引号。这并不能解决这个问题。
    • @BoristheSpider 我认为他正在寻找第二个“以便他可以找到行尾。如果我错了,请纠正我 OP
    • 蜘蛛鲍里斯说的正是我想要的,我编辑了我的问题,也许现在更清楚了
    • 下次考虑用一个例子来说明你的观点。
    • @BoristheSpider .lastindexOf("\"", 1) 将为您获取字符串中 " 的最后一个索引
    猜你喜欢
    • 2013-08-29
    • 2018-07-22
    • 2021-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-23
    • 1970-01-01
    相关资源
    最近更新 更多