Мне потребовалось некоторое время, чтобы понять, что происходит, потому что я использовал одно слово для тестирования кода, но оно может игнорировать знаки препинания. Не могу понять почему, но по какой-то причине он игнорирует пробелы и знаки препинания, но не одновременно. Пока искал проблему, я изменил ****replaceAll("\p{Punct}", ""); к ****replaceAll("[^A-Za-z ]+", "")
Хотя, похоже, он делает то же самое. Но проблема, с которой я здесь сталкиваюсь, заключается в том, что программа распознает одни вещи, но не другие. И я попытался разделить код на две части: сначала удалить знаки препинания, а вторую - удалить пробелы, оба с одинаковым результатом. примером является то, что «поп», «поп», «поп», «поп!» работает, но другим нравится «Никогда нечетное или четное!» нет.
Я даже не знаю, куда идти, не могли бы вы указать мне правильное направление?
import java.util.Scanner;
class Palindrome {
public static void main(String[] args) {
System.out.println("CSE110 Palindrome - TAOLIN DEINIOL\n");
String userInput;
while (true) {
Scanner in = new Scanner(System.in);
System.out.println("Input statement, or type'done' to quit:");
userInput = in.next();
userInput = userInput.toLowerCase();
userInput = userInput.replaceAll("\\p{Punct}", "");
userInput= userInput.replaceAll(" ", "");
if (userInput.equals("done")) {
break;
}
Palindrome(userInput);
}
}
public static boolean Palindrome(int i, int j, String A) {
if (i >= j) {
System.out.println("That is a Palindrome.\n");
return true;
}
if (A.charAt(i) != A.charAt(j)) {
System.out.println("That is NOT a Palindrome.\n");
return false;
}
return Palindrome(i + 1, j - 1, A);
}
public static boolean Palindrome(String A) {
return Palindrome(0, A.length() - 1, A);
}
}
"вроде бы делает то же самое" - нет, один удаляет только знаки препинания, а второй заменяет все, кроме заданных символов, то есть удаляет не только знаки препинания, но и цифры, символы, пробелы и прочее
Вам лучше читать строки с Scanner
, поскольку палиндромы часто представляют собой предложения (в любом случае интересные). Тогда можно делать String s = userInput.codePoints().map(Character::toLowerCase).filter(Character::isAlphabetic).mapToObj(Character::toString).collect(Collectors.joining());boolean isPalindrome = s.equals(new StringBuilder(s).reverse().toString());
Вот и все
Между прочим, тип char
практически не работает начиная с Java 2 и является устаревшим начиная с Java 5. Будучи 16-битным значением, char
физически неспособен представлять большинство символов. Вместо этого научитесь использовать целые числа с кодовой точкой 🔁, как показано в комментарии от g00se.
Задачи-палиндромы обычно задаются в качестве обучающих упражнений, поэтому использование StringBuilder.reverse
является мошенничеством. Кроме того, использование StringBuilder.reverse
фактически выполняет вдвое больше работы, необходимой для проверки палиндрома. Вам нужно только сравнить первую половину строки со второй половиной строки, а не всю строку с ее обратной стороной.
Видимо, это вопрос Java, а не JavaScript.
Хороший способ выяснить, почему ваш код не делает того, что, по вашему мнению, он должен делать, — это отладить его. Любая современная IDE может вам в этом помочь. Или просто распечатывайте значения соответствующих переменных (здесь userInput
) после каждого изменения.
После этого вы увидите, что userInput
имеет значение "Never"
после того, как вы набрали Never odd, or even!
. Это потому, что in.next()
дает вам следующий токен (следующее слово). Если вы замените это на in.nextLine()
, код будет работать как положено. Значит, проблема не имела никакого отношения к звонку replaceAll
.
Спасибо! это сработало. Уму непостижимо, что что-то такое маленькое перенаправило весь код таким образом.
Я внес в вашу программу несколько исправлений и одно дополнение.
import java.text.Normalizer;
import java.util.Scanner;
public class Palindrome {
public void init() {
System.out.println( "CSE110 Palindrome - TAOLIN DEINIOL\n" );
String userInput;
while( true ) {
Scanner in = new Scanner( System.in );
System.out.println( "Input statement, or type'done' to quit:" );
// change "next" to "nextLine", to read a complete entry
userInput = in.nextLine();
userInput = userInput.toLowerCase();
userInput = userInput.replaceAll( "\\p{Punct}", "" );
// remove accents and other modifiers
userInput = Normalizer.normalize( userInput, Normalizer.Form.NFD )
.replaceAll( "[^\\p{ASCII}]", "" );
System.out.println( userInput );
userInput = userInput.replaceAll( " ", "" );
System.out.println( userInput );
if ( userInput.equals( "done" ) ) {
break;
}
// remove the intermediate step, call directly to "isPalindrome"
// change the name of this method, to avoid collision with the name of the class
isPalindrome( 0, userInput.length() -1, userInput );
}
}
public boolean isPalindrome( int i, int j, String A ) {
if ( i >= j ) {
System.out.println( "That is a Palindrome.\n" );
return true;
}
if ( A.charAt( i ) != A.charAt( j ) ) {
System.out.println( "That is NOT a Palindrome.\n" );
return false;
}
return isPalindrome( i + 1, j - 1, A );
}
public static void main( String[] args ) {
Palindrome aa = new Palindrome();
aa.init();
}
}
В основном методе создайте только объект Palindrome и вызовите свой метод init, таким образом я избегаю уродливой (ненужной) статики.
Это работает путем удаления всех небукв [^a-z]
(путем замены на ничего) и использования StringBuilder
для переворачивания символов:
Scanner in = new Scanner(System.in);
while (true) {
System.out.println("Input statement, or type 'done' to quit:");
String userInput = in.nextLine();
if (userInput.equals("done")) {
break;
}
userInput = userInput.toLowerCase().replaceAll("[^a-z]", "");
boolean isPalindrome = new StringBuilder(userInput).reverse().toString().equals(userInput);
System.out.format("%s is%s a palindrome\n", userInput, isPalindrome ? "" : " not");
}
На ваш вопрос дан ответ, но есть еще небольшое предложение. Нетрадиционно иметь обычные методы с такими же именами, как и у включающего класса. В данном случае у вас есть метод под названием «Палиндром». Сначала я подумал, что это конструктор, но потом понял, что это не так. Чтобы избежать путаницы, используйте рекомендуемые соглашения об именах: поскольку это логический метод, его желательно называть
isPalindrome
. И он не должен ничего печатать сам, а вместо этого выполнять печать вmain
после проверки возвращаемого значения.