Tổng quanChia Chuỗi tại ngôn ngữ tự nhiên phá vỡ
tôi gửi Strings đến một máy chủ Text-to-Speech chấp nhận chiều dài tối đa 300 ký tự. Do độ trễ mạng, có thể có sự chậm trễ giữa mỗi phần của lời nói được trả lại, vì vậy tôi muốn chia nhỏ bài phát biểu ở hầu hết các 'tạm dừng tự nhiên' ở bất kỳ nơi nào có thể.
Mỗi yêu cầu của máy chủ đều tốn tiền cho tôi, vì vậy, lý tưởng nhất là tôi gửi chuỗi dài nhất có thể, tối đa các ký tự được phép tối đa.
Đây là thực hiện hiện tại của tôi:
private static final boolean DEBUG = true;
private static final int MAX_UTTERANCE_LENGTH = 298;
private static final int MIN_UTTERANCE_LENGTH = 200;
private static final String FULL_STOP_SPACE = ". ";
private static final String QUESTION_MARK_SPACE = "? ";
private static final String EXCLAMATION_MARK_SPACE = "! ";
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
private static final String COMMA_SPACE = ", ";
private static final String JUST_A_SPACE = " ";
public static ArrayList<String> splitUtteranceNaturalBreaks(String utterance) {
final long then = System.nanoTime();
final ArrayList<String> speakableUtterances = new ArrayList<String>();
int splitLocation = 0;
String success = null;
while (utterance.length() > MAX_UTTERANCE_LENGTH) {
splitLocation = utterance.lastIndexOf(FULL_STOP_SPACE, MAX_UTTERANCE_LENGTH);
if (DEBUG) {
System.out.println("(0 FULL STOP) - last index at: " + splitLocation);
}
if (splitLocation < MIN_UTTERANCE_LENGTH) {
if (DEBUG) {
System.out.println("(1 FULL STOP) - NOT_OK");
}
splitLocation = utterance.lastIndexOf(QUESTION_MARK_SPACE, MAX_UTTERANCE_LENGTH);
if (DEBUG) {
System.out.println("(1 QUESTION MARK) - last index at: " + splitLocation);
}
if (splitLocation < MIN_UTTERANCE_LENGTH) {
if (DEBUG) {
System.out.println("(2 QUESTION MARK) - NOT_OK");
}
splitLocation = utterance.lastIndexOf(EXCLAMATION_MARK_SPACE, MAX_UTTERANCE_LENGTH);
if (DEBUG) {
System.out.println("(2 EXCLAMATION MARK) - last index at: " + splitLocation);
}
if (splitLocation < MIN_UTTERANCE_LENGTH) {
if (DEBUG) {
System.out.println("(3 EXCLAMATION MARK) - NOT_OK");
}
splitLocation = utterance.lastIndexOf(LINE_SEPARATOR, MAX_UTTERANCE_LENGTH);
if (DEBUG) {
System.out.println("(3 SEPARATOR) - last index at: " + splitLocation);
}
if (splitLocation < MIN_UTTERANCE_LENGTH) {
if (DEBUG) {
System.out.println("(4 SEPARATOR) - NOT_OK");
}
splitLocation = utterance.lastIndexOf(COMMA_SPACE, MAX_UTTERANCE_LENGTH);
if (DEBUG) {
System.out.println("(4 COMMA) - last index at: " + splitLocation);
}
if (splitLocation < MIN_UTTERANCE_LENGTH) {
if (DEBUG) {
System.out.println("(5 COMMA) - NOT_OK");
}
splitLocation = utterance.lastIndexOf(JUST_A_SPACE, MAX_UTTERANCE_LENGTH);
if (DEBUG) {
System.out.println("(5 SPACE) - last index at: " + splitLocation);
}
if (splitLocation < MIN_UTTERANCE_LENGTH) {
if (DEBUG) {
System.out.println("(6 SPACE) - NOT_OK");
}
splitLocation = MAX_UTTERANCE_LENGTH;
if (DEBUG) {
System.out.println("(6 MAX_UTTERANCE_LENGTH) - last index at: " + splitLocation);
}
} else {
if (DEBUG) {
System.out.println("Accepted");
}
splitLocation -= 1;
}
}
} else {
if (DEBUG) {
System.out.println("Accepted");
}
splitLocation -= 1;
}
} else {
if (DEBUG) {
System.out.println("Accepted");
}
}
} else {
if (DEBUG) {
System.out.println("Accepted");
}
}
} else {
if (DEBUG) {
System.out.println("Accepted");
}
}
success = utterance.substring(0, (splitLocation + 2));
speakableUtterances.add(success.trim());
if (DEBUG) {
System.out.println("Split - Length: " + success.length() + " -:- " + success);
System.out.println("------------------------------");
}
utterance = utterance.substring((splitLocation + 2)).trim();
}
speakableUtterances.add(utterance);
if (DEBUG) {
System.out.println("Split - Length: " + utterance.length() + " -:- " + utterance);
final long now = System.nanoTime();
final long elapsed = now - then;
System.out.println("ELAPSED: " + TimeUnit.MILLISECONDS.convert(elapsed, TimeUnit.NANOSECONDS));
}
return speakableUtterances;
}
Nó xấu xí do không có khả năng sử dụng regex trong lastIndexOf
. Xấu xí sang một bên, nó thực sự khá nhanh.
vấn đề
Lý tưởng nhất là tôi muốn sử dụng regex cho phép cho một trận đấu trên một trong delimiters lựa chọn đầu tiên của tôi:
private static final String firstChoice = "[.!?" + LINE_SEPARATOR + "]\\s+";
private static final Pattern pFirstChoice = Pattern.compile(firstChoice);
Và sau đó sử dụng một khớp để giải quyết các vị trí:
Matcher matcher = pFirstChoice.matcher(input);
if (matcher.find()) {
splitLocation = matcher.start();
}
Cách thay thế hiện tại của tôi là lưu trữ vị trí của từng dấu phân cách và sau đó chọn vị trí gần nhất MAX_UTTERANCE_LENGTH
Tôi đã thử phương pháp khác nhau để áp dụng các MIN_UTTERANCE_LENGTH
& MAX_UTTERANCE_LENGTH
đến Pattern, vì vậy nó chỉ chụp giữa các giá trị và sử dụng lookarounds để đảo ngược lặp ?<=
, nhưng đây là nơi kiến thức của tôi bắt đầu thất bại tôi:
private static final String poorEffort = "([.!?]{200, 298})\\s+");
Cuối cùng
tôi tự hỏi nếu có của bạn chủ regex có thể đạt được những gì tôi sau và con công ty nếu trong thực tế thực tế, nó sẽ chứng minh hiệu quả hơn?
Tôi cảm ơn bạn trước.
Tài liệu tham khảo:
- Split a string at a natural break (Python)
- Lookarounds
- Regex to Split Tokens With Minimum Size and Delimiters
Câu hỏi hay, tuyệt vời. Tôi hy vọng sẽ thấy một số câu trả lời đến sớm vì đây có vẻ là loại thách thức chính xác mà các chàng trai 'regex' thích. – MattSizzle