用特定逻辑替换字符串中的字符

时间:2016-01-04 06:43:26

标签: java string logic character

我目前正在用Java创建一个简单的Lexer生成器。我差不多完成了,在这里和那里熨了几个虫子,但是遇到了一个问题。

我希望能够在Lexer中包含评论检测,并希望以特定方式包含评论:

  • 注释由存储在字符串中的任何字符集分隔。
    • 示例:single = "//"multi_beg = "/*"multi_end = "*/"
  • 评论字符之间的任何内容都需要用空格替换,因为Lexer使用空格来检测标记之间的差距。 (用void替换可能会导致两个令牌融合在一起)

包括这样的东西在技术上很简单,只需要几个布尔和字符串替换。但是,Lexer还包含可定义的String和Character常量。由于注释字符可以在这些常量中定义,因此当前没有定义字符串或字符时,注释只能是“可执行的”。

此逻辑可能如下所示:

  • 如果当前被包围,则不执行任何操作,直到找到一个无法识别的字符。
  • 如果没有被包裹,并且找到了一个包围的字符,请包住。
  • 如果没有包含,并且找到单个行注释,请替换之后的所有内容并包含注释字符,并使用空格。 (我们处理的是单个字符串,而不是数组,所以引用一行之后的所有内容)
  • 如果没有封装,并且行评论开始,则替换之后的所有内容并包含空格的注释字符,直到多行注释为结束即可。

我的想法完全标记在脑海中,但不知道如何在Java中实现它。

注意:我正在处理一个String数组,并且正在考虑通过增强的for循环来实现这一点,在Scanner中一次处理每一行,在标记堆栈之前处理注释。

for (String s : data) {
    // ???
}

有关如何在Java中实现的任何想法

更新:这就是我想要进/出的样子:

Example

2 个答案:

答案 0 :(得分:2)

这是一个未经测试的实现。测试是最难的部分,要非常小心。

public class CommentStripper {
    private enum State {
        CODE,
        LINE_COMMENT,
        COMMENT,
        STRING
    }
    public static String strip(String input) {
        return strip(input.toCharArray());
    }

    public static String strip(char[] input) {
        State currentState = State.CODE;
        StringBuilder rv = new StringBuilder();
        char[] lineSeparator = System.lineSeparator().toCharArray();
        for (int i = 0; i < input.length; i++) {
            STATE_SWITCH: switch (currentState) {
            case CODE: 
                if (input[i] == '"') {
                    currentState = State.STRING;
                    rv.append(input[i]);
                    break;
                }
                if (input[i] == '/') {
                    if (i + 1 >= input.length) {
                        rv.append(input[i]);
                        break;
                    }
                    if (input[i+1] == '*') {
                        i++;
                        currentState = State.COMMENT;
                        break;
                    } else if (input[i+1] == '/') {
                        i++;
                        currentState = State.LINE_COMMENT;
                        break;
                    }
                }
                rv.append(input[i]);
            break;
            case STRING:
                if (input[i] == '"') {
                    currentState = State.CODE;
                    rv.append(input[i]);
                    break;
                }
                rv.append(input[i]);
                break;
            case COMMENT:
                if (input[i] == '*') {
                    if (i + 1 >= input.length) {
                        break;
                    }
                    if (input[i + 1] == '/') {
                        i++;
                        currentState = State.CODE;
                        break;
                    }
                }
                break;
            case LINE_COMMENT:
                for (int sepIndex = 0; sepIndex < lineSeparator.length; sepIndex++) {
                    if (input[i+sepIndex] != lineSeparator[sepIndex]) {
                        break STATE_SWITCH;
                    }
                }
                i+=lineSeparator.length-1;
                rv.append(lineSeparator);
                currentState = State.CODE;
                break;
            } 
        }
        return rv.toString();
    }
}

初步测试:

import static commentStrip.CommentStripper.strip;
import static org.junit.Assert.*;

import org.junit.Test;

public class CommentStripperTest {

    @Test
    public void test() {
        assertEquals("\"test\"", strip("\"test\"//hello\"test\""));
        assertEquals("\"test\"\"test\"", strip("\"test\"/*hello*/\"test\""));
        assertEquals("test"+System.lineSeparator()+"test", strip("test//linecomment"+System.lineSeparator()+"test"));
        assertEquals("test", strip("test/*test"));
        assertEquals("\"test//hellotest\"", strip("\"test//hellotest\""));
        assertEquals("\"test/*hello*/test\"", strip("\"test/*hello*/test\""));
    }

}

选择基于阵列的简单方法来提高效率。流式API使其膨胀或无效。您必须连接字符串才能使用它。

请注意,无法在字符串文字中放置转义引号。您的问题未指明这一点,因此我省略了对此的处理。

考虑使用像ANTLR这样的解析库,而不是自己编写解析器。

答案 1 :(得分:0)

通常的方法是将此作业留给tokenizer并使注释成为一种空白令牌。