JavaParser Source Viewer

Home|JavaParser/com/github/javaparser/utils/LineSeparator.java
1package com.github.javaparser.utils;
2
3import com.github.javaparser.JavaToken;
4
5import java.util.Optional;
6
7/**
8 * A representation of line endings, that can be used throughout the codebase.
9 * <br>This is to replace {@code Utils.EOL} which is not explicit in representing the system's EOL character.
10 * <br>It also exposes helper methods for, e.g., detection of the line ending of a given string.
11 *
12 * @author Roger Howell
13 * @see <a href="https://github.com/javaparser/javaparser/issues/2647">https://github.com/javaparser/javaparser/issues/2647</a>
14 */
15public enum LineSeparator {
16    /**
17     * The CR {@code \r} line ending is the default line separator for classic MacOS
18     */
19    CR("\r", "CR (\\r)"),
20    /**
21     * The LF {@code \n} line ending is the default line separator for Unix and modern MacOS
22     */
23    LF("\n", "LF (\\n)"),
24    /**
25     * The CRLF {@code \r\n} line ending is the default line separator for Windows
26     */
27    CRLF("\r\n", "CRLF (\\r\\n)"),
28    /**
29     * This line ending is set to whatever the host system's line separator is
30     */
31    SYSTEM(
32            System.getProperty("line.separator"),
33            "SYSTEM : (" + System.getProperty("line.separator")
34                    .replace("\r", "\\r")
35                    .replace("\n", "\\n") +
36                    ")"
37    ),
38    /**
39     * The ARBITRARY line ending can be used where we do not care about the line separator,
40     * only that we use the same one consistently
41     */
42    ARBITRARY("\n", "ARBITRARY (\\n)"),
43    /**
44     * The MIXED line ending is used where strings appear to have multiple different line separators e.g. {@code "line
45     * 1\nline 2\rline 3\r\n"} or {@code "line 1\nline 2\rline 3\nline 4\n"}
46     */
47    MIXED("", "MIXED"),
48    /**
49     * The UNKNOWN line ending can be used in the case where the given string has not yet been analysed to determine its
50     * line separator
51     */
52    UNKNOWN("", "UNKNOWN"),
53    /**
54     * The NONE line ending is used where there are precisely zero line endings e.g. a simple one-line string
55     */
56    NONE("", "NONE");
57
58    private final String text;
59    private final String description;
60
61    LineSeparator(String textString description) {
62        this.text = text;
63        this.description = description;
64    }
65
66    /**
67     * @return The number of times that the given needle is found within the haystack.
68     */
69    private static int count(String haystackString needle) {
70        // Note that if the needle is multiple characters, e.g. \r\n, the difference in string length will be disproportionately affected.
71        return (haystack.length() - haystack.replaceAll(needle"").length()) / needle.length();
72    }
73
74    public static LineSeparator detect(String string) {
75        int countCr = count(string"\r");
76        int countLf = count(string"\n");
77        int countCrLf = count(string"\r\n");
78
79        return getLineEnding(countCrcountLfcountCrLf);
80    }
81
82    public static LineSeparator getLineEnding(int countCrint countLfint countCrLf) {
83        boolean noLineEndings = countCr == 0 && countLf == 0 && countCrLf == 0;
84        if (noLineEndings) {
85            return NONE;
86        }
87
88        boolean crOnly = countCr > 0 && countLf == 0 && countCrLf == 0;
89        if (crOnly) {
90            return CR;
91        }
92        boolean lfOnly = countCr == 0 && countLf > 0 && countCrLf == 0;
93        if (lfOnly) {
94            return LF;
95        }
96
97        // Note that wherever \r\n are found, there will also be an equal number of \r and \n characters found.
98        boolean crLfOnly = countCr == countLf && countLf == countCrLf;
99        if (crLfOnly) {
100            return CRLF;
101        }
102
103        // Not zero line endings, and not a single line ending, thus is mixed.
104        return MIXED;
105    }
106
107    /**
108     * @param ending A string containing ONLY the line separator needle (e.g. {@code \r}, {@code \n}, or {@code \r\n})
109     * @return Where the given ending is a "standard" line separator (i.e. {@code \r}, {@code \n}, or {@code \r\n}),
110     * return that. Otherwise an empty optional.
111     */
112    public static Optional<LineSeparatorlookup(String ending) {
113        if (CR.asRawString().equals(ending)) {
114            return Optional.of(CR);
115        } else if (LF.asRawString().equals(ending)) {
116            return Optional.of(LF);
117        } else if (CRLF.asRawString().equals(ending)) {
118            return Optional.of(CRLF);
119        } else {
120            return Optional.empty();
121        }
122    }
123
124    public static Optional<LineSeparatorlookupEscaped(String ending) {
125        if (CR.asEscapedString().equals(ending)) {
126            return Optional.of(CR);
127        } else if (LF.asEscapedString().equals(ending)) {
128            return Optional.of(LF);
129        } else if (CRLF.asEscapedString().equals(ending)) {
130            return Optional.of(CRLF);
131        } else {
132            return Optional.empty();
133        }
134    }
135
136    public String describe() {
137        // TODO: Return a generated description rather than one hardcoded via constructor.
138        return description;
139    }
140
141    public boolean equalsString(LineSeparator lineSeparator) {
142        return text.equals(lineSeparator.asRawString());
143    }
144
145    public boolean isStandardEol() {
146        // Compare based on the strings to allow for e.g. LineSeparator.SYSTEM
147        return equalsString(LineSeparator.CR) || equalsString(LineSeparator.LF) || equalsString(LineSeparator.CRLF);
148    }
149
150    public String asEscapedString() {
151        String result = text
152                .replace("\r""\\r")
153                .replace("\n""\\n");
154
155        return result;
156    }
157
158    public String asRawString() {
159        return text;
160    }
161
162    // TODO: Determine if this should be used within TokenTypes.java -- thus leaving this as private for now.
163    private Optional<JavaToken.KindasJavaTokenKind() {
164        if(this == CR) {
165            return Optional.of(JavaToken.Kind.OLD_MAC_EOL);
166        } else if(this == LF) {
167            return Optional.of(JavaToken.Kind.UNIX_EOL);
168        } else if(this == CRLF) {
169            return Optional.of(JavaToken.Kind.WINDOWS_EOL);
170        }
171
172        return Optional.empty();
173    }
174
175    @Override
176    public String toString() {
177        return asRawString();
178    }
179
180}
181
MembersX
LineSeparator:NONE
LineSeparator:getLineEnding:Block:lfOnly
LineSeparator:asEscapedString
LineSeparator:ARBITRARY
LineSeparator:asJavaTokenKind
LineSeparator:detect:Block:countCr
LineSeparator:getLineEnding:Block:noLineEndings
LineSeparator:getLineEnding
LineSeparator:CR
LineSeparator:detect:Block:countCrLf
LineSeparator:equalsString
LineSeparator:lookupEscaped
LineSeparator:describe
LineSeparator:CRLF
LineSeparator:UNKNOWN
LineSeparator:isStandardEol
LineSeparator:LF
LineSeparator:text
LineSeparator:LineSeparator
LineSeparator:getLineEnding:Block:crOnly
LineSeparator:toString
LineSeparator:description
LineSeparator:detect:Block:countLf
LineSeparator:detect
LineSeparator:asEscapedString:Block:result
LineSeparator:getLineEnding:Block:crLfOnly
LineSeparator:asRawString
LineSeparator:SYSTEM
LineSeparator:count
LineSeparator:lookup
LineSeparator:MIXED
Members
X