Моя входная строка содержит разделители строк смешанного типа, включая '\r\n', '\r' или '\n'. Я хочу разделить строку и сохранить разделитель строк с предшествующей ему подстрокой. Я следил за двумя сообщениями ниже
Как разделить строку, но сохранить разделители?
Разделить строку Java по новой строке
и придумать что-то вроде:
String input = "1 dog \r\n 2 cat";
String[] output = input.split( "(?<=((\\r\\n)|\\r|\\n))")));
выход ["1 dog\r", "\n", " 2 cat"]
, однако желаемый результат ["1 dog\r\n", " 2 cat"]
.
Если я изменю ввод на String input = "1 dog \r 2 cat";
или String input = "1 dog \n 2 cat";
, мой код может выдать желаемый результат. Пожалуйста, порекомендуйте. Заранее спасибо.
Если вы используете следующее регулярное выражение:(?<=\\r\\n|\\r(?!\\n)|\\n)
для разделения строки, оно будет работать, как задумано.
Что происходит с вашим регулярным выражением, так это то, что когда встречается \r\n
, утверждение просмотра назад будет истинным (?<=\r)
, и оно разделит строку сразу после \r
.
Вот почему я добавил отрицательный прогноз (?!\n)
после \r
, чтобы убедиться, что символ после \r
не является \n
. Это предотвратит раскол между \r
и \n
и сохранит его в целом.
Демонстрация: https://regex101.com/r/H6PNmY/1/ (где я заменил \r
на a
и \n
на b
для удобочитаемости)
Когда вы вернете это в свой код:
String input = "1 dog \r\n 2 cat, 1 car \r 2 planes, 1 apple \n 2 peaches";
String[] output = input.split("(?<=\\r\\n|\\r(?!\\n)|\\n)");
for(int i=0; i<output.length; i++)
{
printASCII(output[i]);
System.out.println("== = ");
}
с printASCII
определяется как:
public static void printASCII(String in)
{
for(int i=0; i<in.length(); i++)
System.out.println("The ASCII value of " + in.charAt(i) + " = " + (int)in.charAt(i) );
}
Это дает вам следующий вывод:
The ASCII value of 1 = 49
The ASCII value of = 32
The ASCII value of d = 100
The ASCII value of o = 111
The ASCII value of g = 103
The ASCII value of = 32
The ASCII value of
= 13
The ASCII value of
= 10
===
The ASCII value of = 32
The ASCII value of 2 = 50
The ASCII value of = 32
The ASCII value of c = 99
The ASCII value of a = 97
The ASCII value of t = 116
The ASCII value of , = 44
The ASCII value of = 32
The ASCII value of 1 = 49
The ASCII value of = 32
The ASCII value of c = 99
The ASCII value of a = 97
The ASCII value of r = 114
The ASCII value of = 32
The ASCII value of
= 13
===
The ASCII value of = 32
The ASCII value of 2 = 50
The ASCII value of = 32
The ASCII value of p = 112
The ASCII value of l = 108
The ASCII value of a = 97
The ASCII value of n = 110
The ASCII value of e = 101
The ASCII value of s = 115
The ASCII value of , = 44
The ASCII value of = 32
The ASCII value of 1 = 49
The ASCII value of = 32
The ASCII value of a = 97
The ASCII value of p = 112
The ASCII value of p = 112
The ASCII value of l = 108
The ASCII value of e = 101
The ASCII value of = 32
The ASCII value of
= 10
===
The ASCII value of = 32
The ASCII value of 2 = 50
The ASCII value of = 32
The ASCII value of p = 112
The ASCII value of e = 101
The ASCII value of a = 97
The ASCII value of c = 99
The ASCII value of h = 104
The ASCII value of e = 101
The ASCII value of s = 115
===
Это показывает, что символы EOL правильно хранятся, как вы просили.
ASCII table:https://www.ibm.com/support/knowledgecenter/en/ssw_aix_72/com.ibm.aix.networkcomm/conversion_table.htm
Вы получаете свой результат ["1 dog\r", "\n", " 2 cat"]
, потому что в вашем шаблоне используется чередование, которое будет соответствовать либо (\r\n)
, либо \r
, либо \n
.
Когда в строке примера встречается \r\n
, утверждение ретроспективного просмотра будет истинным после \r
и впервые разделится.
Тогда обратное утверждение будет истинным после \n
и разделится во второй раз.
Что вы можете сделать, так это использовать \R
в положительном взгляде назад, чтобы утверждать, что слева есть последовательность новой строки юникода:
String input = "1 dog \r\n 2 cat";
String[] output = input.split("(?<=\\R)");
Другой вариант исправить ваше регулярное выражение — сделать его атомная группа:
(?<=(?>\\r\\n|\\r|\\n))
При чтении эта почта, когда \r
сопоставляется в ретроспективном просмотре с использованием атомарной группы, следующий \n
также сопоставляется.
Я думаю, что этот ответ будет выглядеть лучше, если вы объясните причину, по которой регулярное выражение OP не сработало.
@ Аллан, спасибо, я повторно использовал часть вашего printASCII
в демонстрации Java, чтобы перечислить символы, если вы согласны.
@WiktorStribiżew Это справедливо, я добавил объяснение регулярного выражения OP.
Да, но почему \R
работает, вероятно, более интересно, и ответ на вопрос, почему \R
работает, также покажет OP, как исправить их регулярное выражение.
@Thefourthbird: вперед! ;-)
Очень хороший ответ! Использование
\R
лучше моего решения! +1