簡體   English   中英

Python正則表達式全局用空格替換尾隨零

[英]Python regex to globally replace trailing zeros with spaces

作為將浮點數與表格數字數據的小數點分隔符對齊的解決方法,我嘗試使用以下規則找到用空格替換(全局后驗)尾隨零的正則表達式:

  1. 十進制數字后沒有尾隨零
  2. 如果小數點分隔符后的第一個數字為零,請保留它

由於Python正則表達式引擎限制需要固定寬度模式的后視,我無法找到滿意的解決方案。 這是我的嘗試的一個工作示例(Python 3.x); 不要依賴於解決方案中的豎條,為了清晰起見,它們僅在示例中:

import re
# formatmany is just a way to speed up building of multiline string of tabular data
formatmany=lambda f:lambda *s:'\n'.join(f.format(*x) for x in s)

my_list = [[12345, 12.345, 12.345, 12.345],
           [12340, 12.34 , 12.34 , 12.34 ],
           [12345, 12.005, 12.005, 12.005],
           [12340, 12.04 , 12.04 , 12.04 ],
           [12300, 12.3  , 12.3  , 12.3  ],
           [12000, 12.0  , 12.0  , 12    ]]
my_format = formatmany('|{:8d}|{:8.2f}|{:8.3f}|{:8.4f}|')
my_string = my_format(*my_list) # this is the formatted multiline string with trailing zeros

print('\nOriginal string:\n')
print(my_string)
print('\nTry 1:\n')
print(re.sub(r'(?<!\.)0+(?=[^0-9\.]|$)',lambda m:' '*len(m.group()),my_string))
print('\nTry 2:\n')
print(re.sub(r'(\d)0+(?=[^\d]|$)',r'\1',my_string))

打印

Original string:

|   12345|   12.35|  12.345| 12.3450|
|   12340|   12.34|  12.340| 12.3400|
|   12345|   12.01|  12.005| 12.0050|
|   12340|   12.04|  12.040| 12.0400|
|   12300|   12.30|  12.300| 12.3000|
|   12000|   12.00|  12.000| 12.0000|

Try 1:

|   12345|   12.35|  12.345| 12.345 |
|   1234 |   12.34|  12.34 | 12.34  |
|   12345|   12.01|  12.005| 12.005 |
|   1234 |   12.04|  12.04 | 12.04  |
|   123  |   12.3 |  12.3  | 12.3   |
|   12   |   12.0 |  12.0  | 12.0   |

Try 2:

|   12345|   12.35|  12.345| 12.345|
|   1234|   12.34|  12.34| 12.34|
|   12345|   12.01|  12.005| 12.005|
|   1234|   12.04|  12.04| 12.04|
|   123|   12.3|  12.3| 12.3|
|   12|   12.0|  12.0| 12.0|

嘗試1也用整數替換尾隨零,嘗試2取自另一個解決方案,用於替換單個浮點中的尾隨零。 兩者都不令人滿意,因為所需的輸出應該是:

|   12345|   12.35|  12.345| 12.345 |
|   12340|   12.34|  12.34 | 12.34  |
|   12345|   12.01|  12.005| 12.005 |
|   12340|   12.04|  12.04 | 12.04  |
|   12300|   12.3 |  12.3  | 12.3   |
|   12000|   12.0 |  12.0  | 12.0   |

為什么這不是一個重復的問題

  1. Python正則表達式引擎與其他語言引擎略有不同,因此其他語言的解決方案不會自動應用
  2. 尾隨零將被替換,而不是被剝離
  3. 這是關於多線字符串中的許多發生的全局替換,而不僅僅是單個的並發

stribizhev(之前但不滿意)的回答讓我想到了一個通用的解決方案:

re.sub(r'(?<=\.)(\d+?)(0+)(?=[^\d]|$)',lambda m:m.group(1)+' '*len(m.group(2))

您需要更改sub ,如下所示:

print(re.sub(r'(?<=\.)([0-9]+?)(0+)(?=\D|$)',lambda m:m.group(1)+' '*len(m.group(2)), my_string))

請參閱IDEONE演示

這是一個(?<=\\.)([0-9]+?)(0+)(?=\\D|$)正則表達式匹配的演示

正則表達式匹配:

  • (?<=\\.)([0-9]+?) - 一個或多個數字,但如果前面有文字, 盡可能少. (小數分隔符)
  • (0+) - 1個或多個零...
  • (?=\\D|$) - 最多為非數字\\D或字符串$結尾。

這是另一種方法:

my_list = [[12345, 12.345, 12.345, 12.345],
           [12340, 12.340, 12.340, 12.340],
           [12300, 12.300, 12.300, 12.300],
           [12000, 12.000, 12.000, 12.000]]

format_list = ["{:8d}", "{:8.2f}", "{:8.3f}", "{:8.4f}"]

for row in my_list:
    line = ["{:<8}".format(re.sub(r'(\.\d+?)0+', r'\1', y.format(x))) for x,y in zip(row, format_list)]
    print("|{}|".format("|".join(line)))

給出輸出:

|   12345|   12.35|  12.345| 12.345 |
|   12340|   12.34|  12.34 | 12.34  |
|   12300|   12.3 |  12.3  | 12.3   |
|   12000|   12.0 |  12.0  | 12.0   |

你能嘗試使用它,看看它是否有效? ([0-9]+(\\.[0-9]+[1-9])?)(\\.?0+$)

我建議使用字符串格式而不是正則表達式:

int_fmt = '{:>8d}'
general_fmt = '{:>8.5g}'
float_fmt = '{:>8.1f}'
for l in my_list:
    print '|'.join([int_fmt.format(l[0])] + [(float_fmt if int(x)==x else general_fmt).format(x) for x in l[1:]])

輸出:

   12345|  12.345|  12.345|  12.345
   12340|   12.34|   12.34|   12.34
   12300|    12.3|    12.3|    12.3
   12000|    12.0|    12.0|    12.0

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM