Разбить строку по периоду, но строка содержит числа с плавающей запятой

1

У меня есть строка, образованная из имен (без пробелов), разделенных точками. Каждый токен (после периода) может начинаться с [a-zA-Z_] или [ (и заканчивается на ]) или $ (и заканчивается на $).

Примеры:

  • House.Car. [0].Flower
  • House.Car. $ То $
  • House.Car2. $ 4,45 $. [0]
  • House.Car2. $ Abc.def $. [0]

Поэтому мне нужно разделить строку по периоду, но в последних двух примерах я abc.def разбить 4.45 (или abc.def). Все, что окружено $ не должно быть разделено.

Для двух последних примеров я просто хочу создать такой массив:

  • дом
  • car2
  • $ 4.45 $//исправлено, спасибо Сабудж Хассан
  • [0]

или

  • дом
  • car2
  • $ Abc.def $
  • [0]

Я попытался использовать регулярное выражение, но я совершенно неправ.


Мне просто сообщили, что после закрытия $ может быть другая строка, окруженная < и > которая может снова содержать точки, которые я не должен разделять:

  • House.Car.$abc.def$<ghi.jk>.[0].bla

И мне нужно это сделать так:

  • House
  • Car
  • $abc.def$<ghi.jk>
  • [0]
  • bla

Спасибо за вашу помощь.

  • 1
    Какое регулярное выражение вы пробовали?
  • 0
    Куда ушел $ с выхода ??
Показать ещё 2 комментария
Теги:
string
split

3 ответа

2
Лучший ответ

Вам лучше собирать результаты, "ходя" строку в соответствии с .find():

// Note the alternation
private static final Pattern PATTERN 
    = Pattern.compile("\\$[^.$]+(\\.[^.$]+)*\\$|[^.]+");

//

public List<String> matchesForInput(final String input)
{
    final Matcher m = PATTERN.matcher(input);
    final List<String> matches = new ArrayList<>();

    while (m.find())
        matches.add(m.group());

    return matches;
}
  • 0
    Просто из любопытства, почему вы сделали PATTERN постоянной? О, и это должно быть `PATTERN = Pattern.compile (" \\ ...] + ").
  • 0
    @TheGuywithTheHat хорошо, потому что мне нужно создать его только один раз;) После этого я могу создать столько Matcher ов, сколько захочу;)
Показать ещё 7 комментариев
1

Если параметр regex не используется, вы можете написать свой собственный синтаксический анализатор, который будет перебирать один раз по всем символам в вашей строке, проверяя, находится ли символ внутри $...$, [...] или <...>.

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

Такой парсер может выглядеть так

public static List<String> parse(String input){
    //list which will hold retuned tokens
    List<String> tokens = new ArrayList<>();

    // flags representing if currently tested character is inside some of
    // special areas 
    // (at start we are outside of these areas so hey are set to false)
    boolean insideDolar = false;          // $...$
    boolean insideSquareBrackets = false; // [...]
    boolean insideAgleBrackets =false;    // <...>

    // we need some buffer to build tokens, StringBuilder is excellent here
    StringBuilder sb = new StringBuilder();

    // now lets iterate over all characters and decide if we need to add them
    // to token or just add token to result list
    for (char ch : input.toCharArray()){

    // lets update in which area are we
        // finding $ means that we either start or end '$...$' area so 
        // simple negation of flag is enough to update its status
        if (ch == '$') insideDolar = !insideDolar; 
        //updating rest of flags seems pretty obvious 
        else if (ch == '[') insideSquareBrackets = true;
        else if (ch == ']') insideSquareBrackets = false;
        else if (ch == '<') insideAgleBrackets = true;
        else if (ch == '>') insideAgleBrackets = false;

        // So now we know in which area we are, so lets handle special cases
        // if we are handling no dot
        // OR we are handling dot but we are inside either of areas we need 
        // to just add it to token (append it to StringBuilder)
        if (ch != '.' || insideAgleBrackets|| insideDolar || insideSquareBrackets ){
            sb.append(ch);
        }else{// other case means that we are handling dot outside of special 
              // areas where dots are not separators, so now they represents place 
              // to split which means that we don't add it to token, but
              // add value from buffer (current token) to results and reset buffer
              // for next token
            tokens.add(sb.toString());
            sb.delete(0, sb.length());
        }
    }
    // also since we only add value held in buffer to list of tokens when we 
    // find dot on which we split, there is high chance that we will not add 
    // last token to result, because there is no dot after it, so we need to 
    // do it manually after iterating over all characters 
    if (sb.length()>0)//non empty token needs to be added to result
        tokens.add(sb.toString());

    return tokens;
}

и вы можете использовать его как

String  input = "House.Car2.$abc.def$<ghi.jk>.[0]";
for (String s: parse(input))
    System.out.println(s);

вывод:

House
Car2
$abc.def$<ghi.jk>
[0]
  • 0
    Вау! Я надеюсь однажды действительно понять регулярные выражения, но это потрясающе ...
1

Я считаю, что с помощью Pattern/Matcher будет проще. Сырое регулярное выражение:

\$[^$]+\$|\[[^\]]+\]|[^.]+

В коде:

String s = "House.Car2.$4.45$.[0]";
Pattern pattern = Pattern.compile("\\$[^$]+\\$|\\[[^\\]]+\\]|[^.]+");
Matcher matcher = pattern.matcher(s);
while (matcher.find()) {
   System.out.println(matcher.group());
}

Вывод:

House
Car2
$4.45$
[0]

демонстрация ideonde

  • 0
    Я обновил свой вопрос, мне действительно нужны эти $ s.
  • 0
    @ bomba6 Ну, это легко исправить. Вам просто нужно удалить replaceAll . Я отредактирую

Ещё вопросы

Сообщество Overcoder
Наверх
Меню