Cách chia chuỗi "Thequickbrownfoxjumps"
thành chuỗi con có kích thước bằng nhau trong Java. Ví dụ. "Thequickbrownfoxjumps"
4 kích thước bằng nhau sẽ cho đầu ra.
["Theq","uick","brow","nfox","jump","s"]
Câu hỏi tương tự:
Cách chia chuỗi "Thequickbrownfoxjumps"
thành chuỗi con có kích thước bằng nhau trong Java. Ví dụ. "Thequickbrownfoxjumps"
4 kích thước bằng nhau sẽ cho đầu ra.
["Theq","uick","brow","nfox","jump","s"]
Câu hỏi tương tự:
Câu trả lời:
Đây là phiên bản regex one-liner:
System.out.println(Arrays.toString(
"Thequickbrownfoxjumps".split("(?<=\\G.{4})")
));
\G
là một xác nhận có độ rộng bằng 0 phù hợp với vị trí mà trận đấu trước đó kết thúc. Nếu có là không phù hợp trước, nó phù hợp với đầu của đầu vào, giống như \A
. Giao diện kèm theo khớp với vị trí có bốn nhân vật từ cuối trận đấu cuối cùng.
Cả lookbehind và \G
là các tính năng regex tiên tiến, không được hỗ trợ bởi tất cả các hương vị. Hơn nữa, \G
không được thực hiện nhất quán trên các hương vị hỗ trợ nó. Thủ thuật này sẽ hoạt động (ví dụ) trong Java , Perl, .NET và JGSoft, nhưng không phải trong PHP (PCRE), Ruby 1.9+ hoặc TextMate (cả Oniguruma). JavaScript của/y
(cờ dính) không linh hoạt như \G
và không thể được sử dụng theo cách này ngay cả khi JS đã hỗ trợ giao diện.
Tôi nên đề cập rằng tôi không nhất thiết phải đề xuất giải pháp này nếu bạn có các lựa chọn khác. Các giải pháp phi regex trong các câu trả lời khác có thể dài hơn, nhưng chúng cũng tự ghi lại; cái này chỉ là về đối nghịch với điều đó. ;)
Ngoài ra, điều này không hoạt động trong Android, không hỗ trợ việc sử dụng \G
trong lookbehinds.
String.substring()
thay vì biểu thức chính quy, trong khi yêu cầu thêm một vài dòng mã, sẽ chạy ở đâu đó theo thứ tự nhanh hơn 5x ...
(?s)
trong regex : (?s)(?<=\\G.{4})
.
java.util.regex.PatternSyntaxException: Look-behind pattern matches must have a bounded maximum length
Chà, thật dễ dàng để làm điều này với các phép toán số học và chuỗi đơn giản:
public static List<String> splitEqually(String text, int size) {
// Give the list the right capacity to start with. You could use an array
// instead if you wanted.
List<String> ret = new ArrayList<String>((text.length() + size - 1) / size);
for (int start = 0; start < text.length(); start += size) {
ret.add(text.substring(start, Math.min(text.length(), start + size)));
}
return ret;
}
Tôi không nghĩ rằng nó thực sự đáng sử dụng một regex cho việc này.
EDIT: Lý do của tôi không sử dụng regex:
Splitter.fixedLength(4)
theo đề xuất của seanizer.
Điều này rất dễ dàng với Google Guava :
for(final String token :
Splitter
.fixedLength(4)
.split("Thequickbrownfoxjumps")){
System.out.println(token);
}
Đầu ra:
Theq
uick
brow
nfox
jump
s
Hoặc nếu bạn cần kết quả dưới dạng một mảng, bạn có thể sử dụng mã này:
String[] tokens =
Iterables.toArray(
Splitter
.fixedLength(4)
.split("Thequickbrownfoxjumps"),
String.class
);
Tài liệu tham khảo:
Lưu ý: Cấu trúc bộ chia được hiển thị nội tuyến ở trên, nhưng vì Bộ chia là bất biến và có thể tái sử dụng, nên nên lưu trữ chúng trong các hằng số:
private static final Splitter FOUR_LETTERS = Splitter.fixedLength(4);
// more code
for(final String token : FOUR_LETTERS.split("Thequickbrownfoxjumps")){
System.out.println(token);
}
String.join(separator, arrayOrCollection)
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;
}
src.length()
và len
là cả hai int
, cuộc gọi của bạn ceiling
không thực hiện được những gì bạn muốn - hãy xem một số phản hồi khác đang thực hiện như thế nào: (src.length () + len - 1) / len
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;
}
for
các vòng lặp không?
for
vòng lặp thực sự là một lựa chọn 'tự nhiên' hơn cho việc này :-) Cảm ơn bạn đã chỉ ra điều này.
Bạn có thể sử dụng substring
từ String.class
(xử lý ngoại lệ) hoặc từ Apache lang commons (nó xử lý ngoại lệ cho bạn)
static String substring(String str, int start, int end)
Đặt nó trong một vòng lặp và bạn tốt để đi.
substring
phương thức trong String
lớp tiêu chuẩn ?
Tôi muốn giải pháp đơn giản hơn:
String content = "Thequickbrownfoxjumps";
while(content.length() > 4) {
System.out.println(content.substring(0, 4));
content = content.substring(4);
}
System.out.println(content);
substring
triển khai đã thay đổi với Java 7, cập nhật 6 vào giữa năm 2012, khi các trường offset
và count
trường bị xóa khỏi String
lớp. Vì vậy, sự phức tạp của việc substring
chuyển sang tuyến tính từ lâu trước khi câu trả lời này được thực hiện. Nhưng đối với một chuỗi nhỏ như ví dụ, nó vẫn chạy đủ nhanh và đối với các chuỗi dài hơn thì nhiệm vụ này hiếm khi xảy ra trong thực tế.
Đây là một triển khai thực hiện bằng cách sử dụng các luồng 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();
Nó cho đầu ra sau:
[Theq, uick, brow, nfox, jump, s]
String[] result = IntStream.range(0, (input.length()+3)/4) .mapToObj(i -> input.substring(i *= 4, Math.min(i + 4, input.length()))) .toArray(String[]::new);
Đây là phiên bản một lớp sử dụng Java 8 IntStream để xác định các chỉ mục của phần bắt đầu lát:
String x = "Thequickbrownfoxjumps";
String[] result = IntStream
.iterate(0, i -> i + 4)
.limit((int) Math.ceil(x.length() / 4.0))
.mapToObj(i ->
x.substring(i, Math.min(i + 4, x.length())
)
.toArray(String[]::new);
Trong trường hợp bạn muốn phân chia chuỗi bằng nhau về phía sau, ví dụ từ phải sang trái, ví dụ, để phân tách 1010001111
thành [10, 1000, 1111]
, đây là mã:
/**
* @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;
}
tôi sử dụng giải pháp java 8 sau:
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());
}
Giải pháp Java 8 (như thế này nhưng đơn giản hơn một chút):
public static List<String> partition(String string, int partSize) {
List<String> parts = IntStream.range(0, string.length() / partSize)
.mapToObj(i -> string.substring(i * partSize, (i + 1) * partSize))
.collect(toList());
if ((string.length() % partSize) != 0)
parts.add(string.substring(string.length() / partSize * partSize));
return parts;
}
Tôi đã hỏi @Alan Moore trong một bình luận cho giải pháp được chấp nhận về cách xử lý các chuỗi với dòng mới. Ông đề nghị sử dụng DOTALL.
Sử dụng gợi ý của anh ấy, tôi đã tạo ra một mẫu nhỏ về cách thức hoạt động:
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
*/
}
Nhưng tôi cũng thích giải pháp @Jon Skeets trong https://stackoverflow.com/a/3760193/1237974 . Để duy trì trong các dự án lớn hơn, nơi không phải ai cũng có kinh nghiệm như nhau trong các biểu thức chính quy, có lẽ tôi sẽ sử dụng giải pháp Jons.
Một giải pháp vũ phu khác có thể là,
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]);
}
Trường hợp mã chỉ bước qua chuỗi với chuỗi con
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));
}}
Kết quả
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);
}
Đây là phiên bản của tôi dựa trên các luồng RegEx và Java 8. Điều đáng nói là Matcher.results()
phương thức này có sẵn kể từ Java 9.
Bao gồm kiểm tra.
public static List<String> splitString(String input, int splitSize) {
Matcher matcher = Pattern.compile("(?:(.{" + splitSize + "}))+?").matcher(input);
return matcher.results().map(MatchResult::group).collect(Collectors.toList());
}
@Test
public void shouldSplitStringToEqualLengthParts() {
String anyValidString = "Split me equally!";
String[] expectedTokens2 = {"Sp", "li", "t ", "me", " e", "qu", "al", "ly"};
String[] expectedTokens3 = {"Spl", "it ", "me ", "equ", "all"};
Assert.assertArrayEquals(expectedTokens2, splitString(anyValidString, 2).toArray());
Assert.assertArrayEquals(expectedTokens3, splitString(anyValidString, 3).toArray());
}
public static String[] split(String input, int length) throws IllegalArgumentException {
if(length == 0 || input == null)
return new String[0];
int lengthD = length * 2;
int size = input.length();
if(size == 0)
return new String[0];
int rep = (int) Math.ceil(size * 1d / length);
ByteArrayInputStream stream = new ByteArrayInputStream(input.getBytes(StandardCharsets.UTF_16LE));
String[] out = new String[rep];
byte[] buf = new byte[lengthD];
int d = 0;
for (int i = 0; i < rep; i++) {
try {
d = stream.read(buf);
} catch (IOException e) {
e.printStackTrace();
}
if(d != lengthD)
{
out[i] = new String(buf,0,d, StandardCharsets.UTF_16LE);
continue;
}
out[i] = new String(buf, StandardCharsets.UTF_16LE);
}
return out;
}
public static List<String> getSplittedString(String stringtoSplit,
int length) {
List<String> returnStringList = new ArrayList<String>(
(stringtoSplit.length() + length - 1) / length);
for (int start = 0; start < stringtoSplit.length(); start += length) {
returnStringList.add(stringtoSplit.substring(start,
Math.min(stringtoSplit.length(), start + length)));
}
return returnStringList;
}