Упростить разбиваем строку на символы и числа частей


Требования: разобрать строку на блоки цифр и букв. Альфа-персонажи должны быть отделены от числовых, остальные символы будут игнорироваться.

Пример Данных:

Ввод Желаемого Результата
1А [1, А]
12 [12]
12Г [12, Г]
12ABC-SFS513 [12, АВС, ГФС, 513]
ВОЗРАСТ+Ж#ФЕ [ВОЗРАСТ, ВТ, ФЭ]
-12WE- [12, МЫ]
-12- &%3МЫ- [12, 3, МЫ

Вопрос:

Приведенный ниже код решает эту задачу. Однако, я ищу любые предложения по лучшим способом сделать это (может быть, сумасшедший регулярное выражение, используя строку.сплит()? ) или какие-либо изменения, которые могли бы сделать этот код более читабельным/легко следовать.

Код:

private static String VALID_PATTERN = "[0-9]+|[A-Z]+";

private List<String> parse(String toParse){
    List<String> chunks = new LinkedList<String>();
    toParse = toParse + "$"; //Added invalid character to force the last chunk to be chopped off
    int beginIndex = 0;
    int endIndex = 0;
    while(endIndex < toParse.length()){         
        while(toParse.substring(beginIndex, endIndex + 1).matches(VALID_PATTERN)){
            endIndex++;
        }
        if(beginIndex != endIndex){
            chunks.add(toParse.substring(beginIndex, endIndex));    
        } else {
            endIndex++;
        }  
        beginIndex = endIndex;
    }               
    return chunks;
}


48242
12
задан 10 мая 2011 в 01:05 Источник Поделиться
Комментарии
4 ответа

Во-первых, да есть сумасшедшие регулярных выражений вы можете дать строку.сплит:

"[^A-Z0-9]+|(?<=[A-Z])(?=[0-9])|(?<=[0-9])(?=[A-Z])"

Что это означает, разделить на последовательности символов, которые не являются цифрами или буквами, а также между любыми появления буквы следуют цифры или какие-либо числа, затем большой буквы. Хитрость тут в том, чтобы соответствовать пространству между буквой и цифрой (или наоборот), не потребляя буква или цифра. Для этого мы используем смотрю-позади, чтобы соответствовать части до раскола и смотреть вперед, чтобы соответствовать части после раскола.

Однако, как вы наверное, заметили, что выше регулярное выражение-это совсем немного сложнее, чем ваш VALID_PATTERN. Это происходит потому, что вы действительно делаете, пытаясь извлечь определенные части из строки, а не разбивать его.


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

private static final Pattern VALID_PATTERN = Pattern.compile("[0-9]+|[A-Z]+");

private List<String> parse(String toParse) {
List<String> chunks = new LinkedList<String>();
Matcher matcher = VALID_PATTERN.matcher(toParse);
while (matcher.find()) {
chunks.add( matcher.group() );
}
return chunks;
}


Если вы делаете что-то вроде этого больше чем раз, вы, возможно, хотите изменить тело этого метода в метод, метод findAll , который принимает строку и шаблон в качестве аргумента, а затем вызвать его как метод findAll(правильно разобрать, VALID_PATTERN) в разбор.

13
ответ дан 10 мая 2011 в 02:05 Источник Поделиться

Я уверен, что это возможно с какой-то сумасшедшей и обработать .Сплит(), но я бы не регулярные выражения для "простых" задач, таких как эти.

Одна вещь, которую я изменил бы, это проверить, если "пышка" соответствует шаблону. Например, при работе в строке "почтовый индекс ab12", то в настоящее время вы сначала проверьте, если "А" вписывается в шаблон, и потом, если "АБ" , но мы уже знаем, что "А" матчи, так что не нужно делать это снова.

Также добавляем "недопустимый" символ в конец, кажется, неправильный путь к выходу.

Мое предложение было бы сделать так (непроверенных):

private int charType(char c) {
if ('A' <= c && c <= 'Z')
return 1;
else if ('0' <= c && c <= '9')
return 2;
else
return 0;
}

private List<String> parse(String toParse){
List<String> chunks = new LinkedList<String>();
int length = toParse.length();
int beginIndex = 0;
int endIndex = 0;
int currentType;
while (endIndex < length) {
currentType = charType(toParse.charAt(endIndex));
if (currentType != 0) {
do {
endIndex++;
} while (endIndex < length && currentType == charType(toParse.charAt(endIndex)));
chunks.add(toParse.substring(beginIndex, endIndex));
} else {
endIndex++;
}
beginIndex = endIndex;
}
return chunks;
}

4
ответ дан 10 мая 2011 в 02:05 Источник Поделиться

Если тебе пофиг в каком порядке он находится, этот работал для меня

MyString = MyString.replaceAll("[^A-Z ]", "") + " " + MyString.replaceAll("[^0-9 ]", "");

2
ответ дан 10 августа 2012 в 07:08 Источник Поделиться

Вы должны взглянуть на гуава, особенно в CharMatcher и сплиттер. В то время как "ручного" разделения и регулярные выражения, безусловно, нет необходимости, чтобы сделать вашу жизнь сложнее, если уже есть простое и безопасное решение.

1
ответ дан 12 мая 2011 в 06:05 Источник Поделиться