Регулярное выражение удаляет пробелы и пустую строку

#java #regex #java.util.scanner

#java #регулярное выражение #java.util.scanner

Вопрос:

Я пытаюсь создать программу, которая расшифровывает текстовый файл в читаемый текст. Закодированный текст следует двум правилам, он всегда начинается либо с гласной, либо с согласной, это представлено как C или V, за которым следует его позиция в индексе (например: V1C1C3, будет «abc»)

Я создал два массива, содержащих гласные и согласные («0» имеет индекс 0, чтобы остальная часть массива могла начинаться с index1):

 String[] vowels = {"0", "a", "A", "e", "E", "i", "I", "o", "O", "u", "U", "y", "Y"};
String[] cons = {"0","b", "B", "c", "C", "d", "D", "f", "F", "g", "G", "h", "H", "j", "J", "k", "K", "l", "L", "m", "M", "n", "N", "p", "P", "q", "Q", "r", "R", "s", "S", "t", "T", "v", "V", "w", "W", "x", "X", "z", "Z"};
 

Я использую сканер для разделения кода на гласные и согласные, а также для получения значения индекса:

 while(scan.hasNext()){
    String[] parts = scan.nextLine().split("(?=[CV])");

    for (String part : parts) {
        Scanner num = new Scanner(part).useDelimiter("[^0-9] ");
        int value = num.nextInt();

        if(part.charAt(0) == 'C'){
           System.out.print(cons[value]);
        }
        else if (part.charAt(0) == 'V'){
           System.out.print(vowels[value]);
        }
    }
}
 

Зашифрованный текст: V6 C17V7C33V3 V1C23C23C17V3C29 (результат должен быть: я люблю яблоки)

Результат, который я получаю: Iloveapples

P.S: если у меня несколько абзацев зашифрованного текста, сканер останавливается после первого и выдает ошибку. Этого не произойдет, если я использую «scan.next ()» вместо «scan.nextLine ()»

Комментарии:

1. В коде нет ничего, что могло бы обнаружить и вывести недостающие пробелы.

2. @AdrianHHH Итак, вы бы предложили мне создать новый сканер для проверки пробелов или добавить «\ s» в уже существующий сканер?

3. Вам нужен еще один цикл вокруг вашего цикла parts. Выполните разделение на пробелы, затем передайте этот вывод в цикл parts . Выведите пробел в конце вашего нового цикла. В качестве альтернативы вы можете использовать streams или regex для переназначения ваших символов и сохранения пробелов.

Ответ №1:

Кажется, вы хотите, чтобы любая часть, которая не является кодировкой, оставалась неизменной, например, пробелы в приведенном примере, но также могут быть символами, такими как запятые, вопросительные знаки и т.д.

Это означает, что было бы намного лучше использовать замену регулярных выражений, используя регулярные выражения для поиска кодировок, то есть букв C или V цифр.

 private static final String VOWELS = "aAeEiIoOuUyY";
private static final String CONSONANTS = "bBcCdDfFgGhHjJkKlLmMnNpPqQrRsStTvVwWxXzZ";
 
 // Requires Java 9 
public static String decode(String encodedText) {
    return Pattern.compile("[CV]\d ").matcher(encodedText)
            .replaceAll(r -> String.valueOf((r.group().charAt(0) == 'V' ? VOWELS : CONSONANTS)
                                            .charAt(Integer.parseInt(r.group().substring(1)) - 1)));
}
 
 // For Java 1.4 
public static String decode(String encodedText) {
    StringBuffer buf = new StringBuffer();
    Matcher m = Pattern.compile("[CV]\d ").matcher(encodedText);
    while (m.find()) {
        String token = m.group();
        int value = Integer.parseInt(token.substring(1));
        char ch = (token.charAt(0) == 'V' ? VOWELS : CONSONANTS).charAt(value - 1);
        m.appendReplacement(buf, String.valueOf(ch));
    }
    return m.appendTail(buf).toString();
}
 

Тест

 System.out.println(decode("V6 C17V7C33V3 V1C23C23C17V3C29"));
System.out.println(decode("C30C11V3 V1C29C15V3C5, "C36C11V1C31 V1C27V3 V11V7V9 C5V7V5C21C9?""));
 

Вывод

 I love apples
She asked, "What are you doing?"
 

Для полноты картины, вот простой неоптимизированный метод кодирования, используемый для создания этого второго примера выше:

 // For Java 1.5 
public static String encode(String plainText) {
    int index;
    StringBuilder buf = new StringBuilder();
    for (int i = 0; i < plainText.length(); i  ) {
        char ch = plainText.charAt(i);
        if ((index = VOWELS.indexOf(ch)) != -1)
            buf.append('V').append(index   1);
        else if ((index = CONSONANTS.indexOf(ch)) != -1)
            buf.append('C').append(index   1);
        else
            buf.append(ch);
    }
    return (buf.length() == plainText.length() ? plainText : buf.toString());
}
 

Ответ №2:

Первая часть этого кодирует некоторые тестовые фразы. Вторая часть декодирует их, сохраняя знаки препинания.

 String[] vowels = { "0", "a", "A", "e", "E", "i", "I", "o",
        "O", "u", "U", "y", "Y" };
String[] cons = { "0", "b", "B", "c", "C", "d", "D", "f", "F",
        "g", "G", "h", "H", "j", "J", "k", "K", "l", "L", "m",
        "M", "n", "N", "p", "P", "q", "Q", "r", "R", "s", "S",
        "t", "T", "v", "V", "w", "W", "x", "X", "z", "Z" };

String c = String.join("", cons);
String v = String.join("", vowels);
    
String[] testData = { "I Love Applesn",
        "To be or not to be that is the question!n",
        "This also handles (parens) and `single` and "double" quotesn" };
    
// this section iterates over the phrases and encodes them, storing the values in
// a StringBuilder
List<String> coded = new ArrayList<>();
for (String text : testData) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < text.length(); i  ) {
        char ch = text.charAt(i);
        int index = v.indexOf(ch);
        if (index >= 0) {
            sb.append("V").append(index);
            continue;
        }
        index = c.indexOf(ch);
        if (index >= 0) {
            sb.append("C").append(index);
            continue;
        }
        sb.append(ch);
    }
    coded.add(sb.toString());
}
    
for (String code : coded) {
    System.out.println(code);
}
// Now simply search on encoded values or a single character. Keep finding the
// pattern and converting back to a letter.  Punctuation is preserved.
String pat = "([CV]\d |.)";
for (String code : coded) {
    StringBuilder plain = new StringBuilder();
    Matcher m = Pattern.compile(pat).matcher(code);
    while (m.find()) {
        String group = m.group();
        if (group.charAt(0) == 'V') {
            plain.append(v.charAt(
                    Integer.valueOf(group.substring(1))));
        } else if (group.charAt(0) == 'C') {
            plain.append(c.charAt(
                    Integer.valueOf(group.substring(1))));
        } else {
            plain.append(group);
        }
    }
    
    System.out.println(plain);
}
 

Приведенное выше печатает сначала закодированные строки, затем декодированные строки.

 V6 C18V7C33V3 V2C23C23C17V3C29

C32V7 C1V3 V7C27 C21V7C31 C31V7 C1V3 C31C11V1C31 V5C29 C31C11V3 C25V9V3C29C31V5V
7C21!

C32C11V5C29 V1C17C29V7 C11V1C21C5C17V3C29 (C23V1C27V3C21C29) V1C21C5 `C29V5C21C9
C17V3` V1C21C5 "C5V7V9C1C17V3" C25V9V7C31V3C29

I Love Apples
To be or not to be that is the question!
This also handles (parens) and `single` and "double" quotes