วิธีแบ่งสตริง"Thequickbrownfoxjumps"
เป็นสตริงย่อยที่มีขนาดเท่ากันใน Java เช่น. "Thequickbrownfoxjumps"
4 ขนาดเท่ากันควรให้ผลลัพธ์
["Theq","uick","brow","nfox","jump","s"]
คำถามที่คล้ายกัน:
วิธีแบ่งสตริง"Thequickbrownfoxjumps"
เป็นสตริงย่อยที่มีขนาดเท่ากันใน Java เช่น. "Thequickbrownfoxjumps"
4 ขนาดเท่ากันควรให้ผลลัพธ์
["Theq","uick","brow","nfox","jump","s"]
คำถามที่คล้ายกัน:
คำตอบ:
นี่คือเวอร์ชัน regex one-liner:
System.out.println(Arrays.toString(
"Thequickbrownfoxjumps".split("(?<=\\G.{4})")
));
\G
คือการยืนยันความกว้างเป็นศูนย์ที่ตรงกับตำแหน่งที่การแข่งขันก่อนหน้าสิ้นสุดลง ถ้ามีก็ไม่ตรงกับก่อนหน้านี้มันตรงกับจุดเริ่มต้นของการป้อนข้อมูลเช่นเดียวกับ\A
ไม่ตรงกับก่อนหน้านี้มันตรงกับจุดเริ่มต้นของการป้อนข้อมูลเช่นเดียวกับรูปลักษณ์ที่ล้อมรอบจะตรงกับตำแหน่งที่มีอักขระสี่ตัวจากตอนท้ายของการแข่งขันล่าสุด
ทั้ง lookbehind และ\G
เป็นฟีเจอร์ regex ขั้นสูงไม่รองรับทุกรสชาติ นอกจากนี้ยัง\G
ไม่มีการนำไปใช้อย่างสม่ำเสมอในรสชาติที่รองรับ เคล็ดลับนี้จะใช้ได้ผล (เช่น) ในJava , Perl, .NET และ JGSoft แต่ใช้ไม่ได้ในPHP (PCRE), Ruby 1.9+ หรือ TextMate (ทั้ง Oniguruma) /y
(ธงติดหนึบ) ของ JavaScript ไม่ยืดหยุ่นเท่า\G
และไม่สามารถใช้วิธีนี้ได้แม้ว่า JS จะรองรับ lookbehind ก็ตาม
ฉันควรพูดถึงว่าฉันไม่จำเป็นต้องแนะนำวิธีแก้ปัญหานี้หากคุณมีตัวเลือกอื่น โซลูชันที่ไม่ใช่ regex ในคำตอบอื่น ๆ อาจยาวกว่า แต่ก็มีการจัดทำเอกสารด้วยตนเอง อันนี้ตรงกันข้ามมัน ;)
นอกจากนี้ยังใช้ไม่ได้กับ Android ซึ่งไม่รองรับการใช้งาน\G
ในรูปลักษณ์ที่อยู่เบื้องหลัง
String.substring()
แทน regex ในขณะที่ต้องใช้โค้ดเพิ่มอีกสองสามบรรทัดจะทำงานที่ใดก็ได้ตามลำดับที่เร็วขึ้น 5 เท่า ...
(?s)
ใน regex (?s)(?<=\\G.{4})
นี้:
java.util.regex.PatternSyntaxException: Look-behind pattern matches must have a bounded maximum length
มันค่อนข้างง่ายที่จะทำสิ่งนี้ด้วยการคำนวณทางคณิตศาสตร์และสตริงอย่างง่าย:
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;
}
ฉันไม่คิดว่าจะคุ้มค่ากับการใช้ regex สำหรับสิ่งนี้
แก้ไข: เหตุผลของฉันที่ไม่ใช้ regex:
Splitter.fixedLength(4)
ตามที่ seanizer แนะนำ
สิ่งนี้ง่ายมากกับ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);
}
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()
และlen
เป็นทั้งคู่การint
โทรของคุณceiling
จึงไม่บรรลุผลตามที่คุณต้องการลองดูว่าคำตอบอื่น ๆ ทำอย่างไร: (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
ลูปไหม?
for
วนซ้ำเป็นการใช้ทางเลือกที่ 'เป็นธรรมชาติ' มากกว่าสำหรับสิ่งนี้ :-) ขอบคุณที่ชี้ให้เห็นสิ่งนี้
คุณสามารถใช้substring
จากString.class
(การจัดการข้อยกเว้น) หรือจากApache lang commons (จัดการข้อยกเว้นสำหรับคุณ)
static String substring(String str, int start, int end)
ใส่ไว้ในวงและคุณก็พร้อมที่จะไป
substring
วิธีการในString
คลาสมาตรฐาน?
นี่คือเวอร์ชันซับเดียวซึ่งใช้Java 8 IntStreamเพื่อกำหนดดัชนีของจุดเริ่มต้นของสไลซ์:
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);
ฉันต้องการวิธีง่ายๆนี้:
String content = "Thequickbrownfoxjumps";
while(content.length() > 4) {
System.out.println(content.substring(0, 4));
content = content.substring(4);
}
System.out.println(content);
substring
ใช้งานเปลี่ยนไปด้วย Java 7 อัปเดต 6 ในกลางปี 2555 เมื่อฟิลด์offset
และcount
ถูกลบออกจากString
คลาส ดังนั้นความซับซ้อนของการsubstring
เปลี่ยนเป็นเชิงเส้นมานานก่อนที่จะมีคำตอบนี้ แต่สำหรับสตริงขนาดเล็กเช่นตัวอย่างมันยังคงทำงานได้เร็วพอและสำหรับสตริงที่ยาวขึ้น ... งานนี้ไม่ค่อยเกิดขึ้นในทางปฏิบัติ
นี่คือการใช้งานซับหนึ่งโดยใช้สตรีม 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]
String[] result = IntStream.range(0, (input.length()+3)/4) .mapToObj(i -> input.substring(i *= 4, Math.min(i + 4, input.length()))) .toArray(String[]::new);
ในกรณีที่คุณต้องการแยกสตริงไปข้างหลังเท่า ๆ กันเช่นจากขวาไปซ้ายตัวอย่างเช่นเพื่อแยก1010001111
ไป[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;
}
ฉันใช้โซลูชัน 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());
}
โซลูชัน Java 8 (แบบนี้แต่ง่ายกว่าเล็กน้อย):
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;
}
ฉันถาม @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);
}
นี่คือเวอร์ชันของฉันที่ใช้สตรีม RegEx และ Java 8 มันคุ้มที่จะพูดถึงเรื่องนั้นMatcher.results()
วิธีการดังกล่าวพร้อมใช้งานตั้งแต่ Java 9
รวมการทดสอบ
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;
}