탈출 한 쉼표를 무시하는 동안 쉼표로 분리 된 문자열을 분할하는 방법은 무엇입니까?
문제
추가 매개 변수 인 Escape Char를 얻는 StringUtils.commadelimitedListToStringArray 함수의 확장 버전을 작성해야합니다.
그래서 내 부르기 :
commaDelimitedListToStringArray("test,test\\,test\\,test,test", "\\")
반환해야합니다 :
["test", "test,test,test", "test"]
현재의 시도는 String.split ()를 사용하여 정규식을 사용하여 문자열을 분할하는 것입니다.
String[] array = str.split("[^\\\\],");
그러나 반환 된 배열은 다음과 같습니다.
["tes", "test\,test\,tes", "test"]
어떤 아이디어?
해결책
정규 표현
[^\\],
"백 슬래시가 아닌 캐릭터와 쉼표가 뒤 따르는 캐릭터 일치"를 의미합니다. 이것이 바로 다음과 같은 패턴입니다. t,
일치하기 때문에 t
백 슬래시가 아닌 캐릭터입니다.
나는 당신이 일종의 사용이 필요하다고 생각합니다 부정적인 외모, 캡처하기 위해 ,
a \
앞의 캐릭터를 캡처하지 않고도
(?<!\\),
(BTW, 나는 이것을 더 읽기 쉽게 만들기 위해 의도적으로 백 슬래시를 이중으로 이루어지지 않았다는 점에 유의하십시오)
다른 팁
노력하다:
String array[] = str.split("(?<!\\\\),");
기본적으로 이것은 쉼표가 두 개의 백 슬래시가 선행되는 경우를 제외하고는 쉼표에서 분할됩니다. 이것을 a라고합니다 부정적인 외관은 제로 폭의 주장입니다.
향후 참조를 위해 다음은 다음과 같은 완전한 방법입니다.
public static String[] commaDelimitedListToStringArray(String str, String escapeChar) {
// these characters need to be escaped in a regular expression
String regularExpressionSpecialChars = "/.*+?|()[]{}\\";
String escapedEscapeChar = escapeChar;
// if the escape char for our comma separated list needs to be escaped
// for the regular expression, escape it using the \ char
if(regularExpressionSpecialChars.indexOf(escapeChar) != -1)
escapedEscapeChar = "\\" + escapeChar;
// see http://stackoverflow.com/questions/820172/how-to-split-a-comma-separated-string-while-ignoring-escaped-commas
String[] temp = str.split("(?<!" + escapedEscapeChar + "),", -1);
// remove the escapeChar for the end result
String[] result = new String[temp.length];
for(int i=0; i<temp.length; i++) {
result[i] = temp[i].replaceAll(escapedEscapeChar + ",", ",");
}
return result;
}
Matt B가 말했듯이 [^\\],
쉼표 앞의 캐릭터를 구분 기의 일부로 해석 할 것입니다.
"test\\\\\\,test\\\\,test\\,test,test"
-(split)->
["test\\\\\\,test\\\\,test\\,tes" , "test"]
Drvdijk가 말했듯이 (?<!\\),
오해의 백 슬래시를 잘못 해석 할 것입니다.
"test\\\\\\,test\\\\,test\\,test,test"
-(split)->
["test\\\\\\,test\\\\,test\\,test" , "test"]
-(unescape commas)->
["test\\\\,test\\,test,test" , "test"]
나는 또한 등 슬래시를 탈출 할 수있을 것으로 기대합니다 ...
"test\\\\\\,test\\\\,test\\,test,test"
-(split)->
["test\\\\\\,test\\\\" , "test\\,test" , "test"]
-(unescape commas and backslashes)->
["test\\,test\\" , "test,test" , "test"]
Drvdijk가 제안했다 (?<=(?<!\\\\)(\\\\\\\\){0,100}),
최대 100 개의 백 슬래시로 끝나는 요소가있는 목록에 적합합니다. 이것은 충분히 ...하지만 왜 한도입니까? 더 효율적인 방법이 있습니까 (욕심이없는 것처럼 보이지 않습니까? 유효하지 않은 문자열은 어떻습니까?
나는 일반적인 솔루션을 위해 잠시 검색 한 다음 직접 썼다.
내 대답은 탈출 문자를 매개 변수로 받아들이지 않습니다.
public static List<String> commaDelimitedListStringToStringList(String list) {
// Check the validity of the list
// ex: "te\\st" is not valid, backslash should be escaped
if (!list.matches("^(([^\\\\,]|\\\\,|\\\\\\\\)*(,|$))+")) {
// Could also raise an exception
return null;
}
// Matcher for the list elements
Matcher matcher = Pattern
.compile("(?<=(^|,))([^\\\\,]|\\\\,|\\\\\\\\)*(?=(,|$))")
.matcher(list);
ArrayList<String> result = new ArrayList<String>();
while (matcher.find()) {
// Unescape the list element
result.add(matcher.group().replaceAll("\\\\([\\\\,])", "$1"));
}
return result;
}
패턴에 대한 설명 (Escaped) :
(?<=(^|,))
앞으로 문자열의 시작 또는 a ,
([^\\,]|\\,|\\\\)*
구성된 요소 \,
, \\
또는 캐릭터는 아무것도 아닙니다 \
...도 아니다 ,
(?=(,|$))
뒤에는 문자열의 끝 또는 a가 있습니다 ,
패턴이 단순화 될 수 있습니다.
3 개의 파싱으로도 (matches
+ find
+ replaceAll
),이 방법은 drvdijk가 제안한 방법보다 빠릅니다. 특정 파서를 작성하여 여전히 최적화 할 수 있습니다.
또한, 한 캐릭터 만 특별하면 탈출 캐릭터를 가질 필요가있는 것은 무엇입니까? 단순히 두 배가 될 수 있습니다 ...
public static List<String> commaDelimitedListStringToStringList2(String list) {
if (!list.matches("^(([^,]|,,)*(,|$))+")) {
return null;
}
Matcher matcher = Pattern.compile("(?<=(^|,))([^,]|,,)*(?=(,|$))")
.matcher(list);
ArrayList<String> result = new ArrayList<String>();
while (matcher.find()) {
result.add(matcher.group().replaceAll(",,", ","));
}
return result;
}