Разделить строку на подстроки равной длины в Java
как разделить строку "Thequickbrownfoxjumps"
к подстрокам одинакового размера в Java.
Например. "Thequickbrownfoxjumps"
из 4 равных размеров должен дать выход.
["Theq","uick","brow","nfox","jump","s"]
Аналогичный Вопрос:
16 ответов:
вот регулярное выражение однострочной версии:
System.out.println(Arrays.toString( "Thequickbrownfoxjumps".split("(?<=\G.{4})") ));
\G
является утверждением нулевой ширины, которое соответствует позиции, где закончился предыдущий матч. Если есть был нет предыдущего совпадения, он соответствует началу ввода, так же, как\A
. Заключительный lookbehind соответствует позиции, которая составляет четыре символа с конца последнего матча.оба lookbehind и
\G
расширенные функции регулярных выражений, не поддерживаемые всеми вкусами. Кроме того,\G
не реализуется последовательно через ароматы, которые поддерживают его. Этот трюк будет работать (например) в Java, Perl, .NET и JGSoft, но не в PHP (PCRE), Ruby 1.9+ или TextMate (оба Oniguruma). В JavaScript/y
(липкий флаг) не так гибко, как\G
, и не может быть использован таким образом, даже если JS поддерживает lookbehind.Я должен упомянуть, что я не должен рекомендую это решение, если у вас есть другие варианты. Нерегулярные решения в других ответах могут быть длиннее, но они также самодокументированы; это просто о напротив об этом. ;)
кроме того, это не работает в Android, который не поддерживает использование
\G
в lookbehinds.
это очень легко с Google Guava:
for(final String token : Splitter .fixedLength(4) .split("Thequickbrownfoxjumps")){ System.out.println(token); }
выход:
Theq uick brow nfox jump s
или если вам нужен результат в виде массива, вы можете использовать этот код:
String[] tokens = Iterables.toArray( Splitter .fixedLength(4) .split("Thequickbrownfoxjumps"), String.class );
ссылки:
Примечание: конструкция сплиттера показана выше, но так как сплиттеры являются неизменяемыми и многоразовыми, это хорошая практика, чтобы хранить их в константы:
private static final Splitter FOUR_LETTERS = Splitter.fixedLength(4); // more code for(final String token : FOUR_LETTERS.split("Thequickbrownfoxjumps")){ System.out.println(token); }
public static String[] split(String src, int len) { String[] result = new String[(int)Math.ceil((double)src.length()/(double)len)]; for (int i=0; i<result.length; i++) result[i] = src.substring(i*len, Math.min(src.length(), (i+1)*len)); return result; }
public String[] splitInParts(String s, int partLength) { int len = s.length(); // Number of parts int nparts = (len + partLength - 1) / partLength; String parts[] = new String[nparts]; // Break into parts int offset= 0; int i = 0; while (i < nparts) { parts[i] = s.substring(offset, Math.min(offset + partLength, len)); offset += partLength; i++; } return parts; }
можно использовать
substring
СString.class
(обработка исключений) или Apache Lang commons (он обрабатывает исключения для вас)static String substring(String str, int start, int end)
положите его в петлю, и вы хорошо идти.
Я бы предпочел это простое решение:
String content = "Thequickbrownfoxjumps"; while(content.length() > 4) { System.out.println(content.substring(0, 4)); content = content.substring(4); } System.out.println(content);
в случае, если вы хотите разделить строку поровну назад, т. е. справа налево, например, разделить
1010001111
to[10, 1000, 1111]
, вот код:/** * @param s the string to be split * @param subLen length of the equal-length substrings. * @param backwards true if the splitting is from right to left, false otherwise * @return an array of equal-length substrings * @throws ArithmeticException: / by zero when subLen == 0 */ public static String[] split(String s, int subLen, boolean backwards) { assert s != null; int groups = s.length() % subLen == 0 ? s.length() / subLen : s.length() / subLen + 1; String[] strs = new String[groups]; if (backwards) { for (int i = 0; i < groups; i++) { int beginIndex = s.length() - subLen * (i + 1); int endIndex = beginIndex + subLen; if (beginIndex < 0) beginIndex = 0; strs[groups - i - 1] = s.substring(beginIndex, endIndex); } } else { for (int i = 0; i < groups; i++) { int beginIndex = subLen * i; int endIndex = beginIndex + subLen; if (endIndex > s.length()) endIndex = s.length(); strs[i] = s.substring(beginIndex, endIndex); } } return strs; }
вот реализация одного лайнера с использованием потоков Java8:
String input = "Thequickbrownfoxjumps"; final AtomicInteger atomicInteger = new AtomicInteger(0); Collection<String> result = input.chars() .mapToObj(c -> String.valueOf((char)c) ) .collect(Collectors.groupingBy(c -> atomicInteger.getAndIncrement() / 4 ,Collectors.joining())) .values();
это дает следующий результат:
[Theq, uick, brow, nfox, jump, s]
Я спросил @Alan Moore в комментарии к принято решение как строки с новыми строками могут быть обработаны. Он предложил использовать DOTALL.
используя его предложение я создал небольшой пример того, как это работает:
public void regexDotAllExample() throws UnsupportedEncodingException { final String input = "The\nquick\nbrown\r\nfox\rjumps"; final String regex = "(?<=\G.{4})"; Pattern splitByLengthPattern; String[] split; splitByLengthPattern = Pattern.compile(regex); split = splitByLengthPattern.split(input); System.out.println("---- Without DOTALL ----"); for (int i = 0; i < split.length; i++) { byte[] s = split[i].getBytes("utf-8"); System.out.println("[Idx: "+i+", length: "+s.length+"] - " + s); } /* Output is a single entry longer than the desired split size: ---- Without DOTALL ---- [Idx: 0, length: 26] - [B@17cdc4a5 */ //DOTALL suggested in Alan Moores comment on SO: https://stackoverflow.com/a/3761521/1237974 splitByLengthPattern = Pattern.compile(regex, Pattern.DOTALL); split = splitByLengthPattern.split(input); System.out.println("---- With DOTALL ----"); for (int i = 0; i < split.length; i++) { byte[] s = split[i].getBytes("utf-8"); System.out.println("[Idx: "+i+", length: "+s.length+"] - " + s); } /* Output is as desired 7 entries with each entry having a max length of 4: ---- With DOTALL ---- [Idx: 0, length: 4] - [B@77b22abc [Idx: 1, length: 4] - [B@5213da08 [Idx: 2, length: 4] - [B@154f6d51 [Idx: 3, length: 4] - [B@1191ebc5 [Idx: 4, length: 4] - [B@30ddb86 [Idx: 5, length: 4] - [B@2c73bfb [Idx: 6, length: 2] - [B@6632dd29 */ }
но мне нравится решение @Jon Skeets в https://stackoverflow.com/a/3760193/1237974 тоже. Для ремонтопригодности в больших проектах, где не все одинаково опытны в регулярных выражениях, я бы, вероятно, использовал Jons решение.
другое решение грубой силы может быть,
String input = "thequickbrownfoxjumps"; int n = input.length()/4; String[] num = new String[n]; for(int i = 0, x=0, y=4; i<n; i++){ num[i] = input.substring(x,y); x += 4; y += 4; System.out.println(num[i]); }
где код просто проходит через строку с подстроками
import static java.lang.System.exit; import java.util.Scanner; import Java.util.Arrays.*; public class string123 { public static void main(String[] args) { Scanner sc=new Scanner(System.in); System.out.println("Enter String"); String r=sc.nextLine(); String[] s=new String[10]; int len=r.length(); System.out.println("Enter length Of Sub-string"); int l=sc.nextInt(); int last; int f=0; for(int i=0;;i++){ last=(f+l); if((last)>=len) last=len; s[i]=r.substring(f,last); // System.out.println(s[i]); if (last==len)break; f=(f+l); } System.out.print(Arrays.tostring(s)); }}
результат
Enter String Thequickbrownfoxjumps Enter length Of Sub-string 4 ["Theq","uick","brow","nfox","jump","s"]
@Test public void regexSplit() { String source = "Thequickbrownfoxjumps"; // define matcher, any char, min length 1, max length 4 Matcher matcher = Pattern.compile(".{1,4}").matcher(source); List<String> result = new ArrayList<>(); while (matcher.find()) { result.add(source.substring(matcher.start(), matcher.end())); } String[] expected = {"Theq", "uick", "brow", "nfox", "jump", "s"}; assertArrayEquals(result.toArray(), expected); }
вот моя версия, основанная на регулярных выражениях и потоках Java 8. Стоит отметить, что
Matcher.results()
метод доступен с Java 9.
Я использую следующее решение java 8:
public static List<String> splitString(final String string, final int chunkSize) { final int numberOfChunks = (string.length() + chunkSize - 1) / chunkSize; return IntStream.range(0, numberOfChunks) .mapToObj(index -> string.substring(index * chunkSize, Math.min((index + 1) * chunkSize, string.length()))) .collect(toList()); }