【问题标题】:Formatting a string containing operations and digits格式化包含操作和数字的字符串
【发布时间】:2018-08-08 14:06:16
【问题描述】:

我只想格式化一个包含操作和数字的字符串。

例如: 1035+56-7894*9985.31,035+56-7,894*9,985.3

我只需要每 3 位数添加一个逗号。 我只想处理数字并忽略操作和其他任何不是数字的内容。

【问题讨论】:

  • 我只需要每 3 位数添加一个逗号——你可能实际上不想这样做。格式化(十进制)数字取决于区域设置。你应该只有一个数字,让操作系统弄清楚如何显示它。为此有格式说明符。我也对你的问题投了反对票,因为你没有表现出任何努力或任何事情

标签: java android regex kotlin


【解决方案1】:

您可以使用 Kotlins Regex #replace 替换数字并保留其他所有内容:

val input = "1035+56-7894*9985.3"

val numberRegex = Regex("[\\d,.]+") // this actually filters out consecutives digits, commas and dots 

val result = numberRegex.replace(input) { 
    val num = BigDecimal(it.value)
    "%,.2f".format(Locale.US, num)
}

println(result)

将为您的示例打印以下内容:

1,035.00+56.00-7,894.00*9,985.30

或者,如果您确实必须保留小数位,请改用以下格式:

"%,.${max(0, num.stripTrailingZeros().scale())}f".format(Locale.US, num)

将打印:

1,035+56-7,894*9,985.3

【讨论】:

  • 请停止攻击我的回答,谢谢。我们的两个答案都是次优的,因为在生产中我们不会远程使用单个正则表达式来解析算术表达式,我们会使用某种类型的解析器。你是雷克萨斯,我只是丰田,但使用解析器将是玛莎拉蒂。
  • 我不想攻击你的答案......我只是想知道,我总是很好奇。也许有什么我没有考虑到……这就是我问的原因。关于“运算符定位”,就像我解释您的代码一样(它在运算符的边界上拆分并检查条件中的运算符)。
  • 我支持你,你的回答比我的好。最好只隔离数字,但我不认为像你那样使用正则表达式 API。
  • 我在这个网站上花费的时间方式太多了,在cmets中很容易误读某人的意图,因为我们看不到对方的真实情绪。
  • 你试过了吗?它还应该正确格式化您的示例。请注意,如果有更多的事情需要考虑,您可能需要一个解析器。我使用的正则表达式有以下缺陷:不捕获负号,也捕获一对多 ,. 或其组合,如果数字丢失,它们肯定是没有数字。正则表达式也可以改进以考虑这一点,但是它不再那么可读了。
【解决方案2】:

这是一个非常接近您的确切预期输出的脚本:

String input = "1035+56-7894*9985.3";
String[] parts = input.split("(?<=[+*/-])|(?=[+*/-])");
StringBuilder sb = new StringBuilder("");
for (String part : parts) {
    if (!part.equals("+") && !part.equals("-") && !part.equals("*") && !part.equals("/")) {
        double num = Double.parseDouble(part);
        StringBuilder temp = new StringBuilder();
        Formatter formatter = new Formatter(temp, Locale.US);
        formatter.format("%,.2f", num);
        sb.append(temp);
    }
    else {
        sb.append(part);
    }
}

System.out.println(sb);

1,035.00+56.00-7,894.00*9,985.30

Demo

这个答案的秘诀是按照以下模式拆分算术字符串:

(?<=[+*/-])|(?=[+*/-])

这将在操作符号之前或之后拆分,同时将这些符号保留为结果数组中的项目。这使我们可以轻松地迭代字符串数组,然后格式化数字,这样可以在以后需要重建原始算术表达式时保留符号。

然后,对于每个数字,我们将其格式化为带有逗号千位分隔符的两位小数。

【讨论】:

  • 在拆分时选择运算符而不是仅仅过滤掉数字是否有特定的原因?请注意,您还可以使用when“简化”您的if,如下所示:when (part) { "+","-","*","/" -&gt; sb.append(part); else -&gt; { ... }
  • @Roland 谁说我要找接线员?我在操作员两侧的边界处分裂。但是,你让我刚刚意识到我错过了一个极端情况:负数。在我解决这个问题之前,我会等待 OP 投诉。
【解决方案3】:

下面的代码通过在格式化表达式时动态更改小数点后的位数来添加到“Tim Biegeleisen”解决方案。

1) Demo.class:----------

public class Demo extends AppCompatActivity {

private EditText edt;
private TextView tv;
private Button b;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.demo);

    edt = (EditText) findViewById(R.id.edt);
    tv = (TextView) findViewById(R.id.tv);
    b = (Button) findViewById(R.id.b);
    b.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            StringBuilder sb = new StringBuilder();
            String input = edt.getText().toString();
            if (!input.isEmpty()) {
                String[] parts = input.split("(?<=[+*/-])|(?=[+*/-])");
                for (String part : parts) {
                    if (!part.equals("+") && !part.equals("-") && !part.equals("*") && !part.equals("/")) {
                        double num = Double.parseDouble(part);
                        StringBuilder temp = new StringBuilder();
                        if (!isValidInteger(part)) { // if number is a decimal
                            int number_of_digits_after_decimal_point = 2;
                            try {
                                String[] part_split = part.split("\\."); // split number based on "."
                                if (part_split.length == 2) {
                                        number_of_digits_after_decimal_point = part_split[1].length(); // set number_of_digits_after_decimal_point to be equal to the
                                    // length of the string after the decimal point.
                                }
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                            Formatter formatter = new Formatter(temp, Locale.US);
                            formatter.format("%,." + number_of_digits_after_decimal_point + "f", num);
                            sb.append(temp);
                        } else { // if number is an integer
                            Formatter formatter = new Formatter(temp, Locale.US);
                            formatter.format("%,.0f", num);
                            sb.append(temp);
                        }
                    } else {
                        sb.append(part);
                    }
                }
            } else {
                Toast.makeText(getApplicationContext(), "Empty", Toast.LENGTH_LONG).show();
            }

            tv.setText(sb.toString());
        }
    });
}

public static boolean isValidInteger(String value) {
    if (value == null) {
        return false;
    } else {
        try {
            Integer val = Integer.valueOf(value);
            if (val != null)
                return true;
            else
                return false;
        } catch (NumberFormatException e) {
            e.printStackTrace();
            return false;
        }
    }
}

}

2) demo.xml:------

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<EditText
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="20dp"
    android:layout_gravity="center"
    android:id="@+id/edt"
    android:hint="Input"/>

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="20dp"
    android:layout_gravity="center"
    android:text="Output"
    android:id="@+id/tv"/>

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="20dp"
    android:layout_gravity="center"
    android:text="Convert"
    android:id="@+id/b"/>

</LinearLayout>

3) 输出:---------

【讨论】:

  • 当地环境不错。否则,它会使用手机的区域设置,这意味着如果区域设置不是美国,则不会产生准确的格式。
【解决方案4】:

这是我的解决方案,特定于语言环境:

    String startString = "1035+56-7894*9985.3";
    String signs = startString.replaceAll("[^-+*/]", "") + " ";
    String[] numbers = startString
        .replaceAll(",", ".")
        .replaceAll("[-+*/]", " ")
        .split(" ");

    DecimalFormat nf = new DecimalFormat("#,###.#");

    StringBuilder targetString = new StringBuilder();
    for (int i = 0; i < numbers.length; i++) {
        targetString.append(nf.format(Double.parseDouble(numbers[i]))).append(signs, i, i + 1);
    }
    targetString = new StringBuilder(targetString.toString().trim());

    System.out.println(targetString);

打印:

1,035+56-7,894*9,985.3

1.035+56-7.894*9.985,3

取决于区域设置。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-24
    • 1970-01-01
    • 1970-01-01
    • 2022-06-20
    • 2012-11-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多