正则表达式:处理字符串数字的可靠方法

时间:2018-07-11 01:59:45

标签: php regex pcre

编辑:

我不知道是否甚至可以在正则表达式中重新创建它,而@Paul Crovella指出这可能不适合解决问题,但只是为了好玩,我想这样做:

  1. 从右到左开始。匹配第一个字符,即点号或逗号/(?<seperator>[.,])\d+$/
  2. 重置指针并捕获每个数字,直到递归地捕获小数字符为止(除捕获数字外,不捕获其他任何字符)/(?<number>(?:\d+[^\1])+\d+)/
  3. 获取小数位数/(?<decimal)\d+(?<=\1)/

其他规则

  • 如果只有一个[。,],则是小数点
  • 如果这些[。,\ h]中只有一个,那就是hunderds /数千分隔符
  • 如果多次发现第一个捕获的非数字字符,则为hunderds /千位分隔符。
  • hunderds /数千总是相同的,因此应该有可能写一个递归前瞻,该前瞻总是停在字符处,并用数字“填充”一个组

原文:

我正在用PHP建立一个在单位之间转换的类。到目前为止,我已经完成了所有工作,现在我正在尝试创建一种健壮的方法来将输入字符串转换为浮点数。

以下是我的班级应该处理的一些测试字符串:

123456789
1234567.89
1234567,89
1,234,567.89
1.234.567,89
123 456 789
1 234 567.89
1 234 567,89

要使其可行,我必须做一些假设:

  • 字符串可以是整数
  • 该字符串可以用[.,]分隔小数位
  • 可以将字符串分组(以成百上千的形式,用[.,\h]分隔
  • 分隔符是一致的并且彼此不同

我认为最好的“执行一次,正确执行”的方式是使用正则表达式解决此问题。

首先,您必须收集第一个分隔符

/^\d+(?<s>[.,\h])/

然后您必须重置指针并向后引用符号

/^(?<b>(\d+)${s}(\d+))/

我不希望分隔符出现在实际的组中,但是我不知道该如何实现。

下一步是将[^${s}](?<d>\d+)匹配到小数组。

最后将两个数字加在一起

return (float) $matches['b'] . '.' . $matches['d'];

我想出了一些解决方案,但没有一个能很好地解决问题。我希望社区提供一些意见。请提供每个块的操作说明,以便我向您学习。

最诚挚的问候。

P.S。奖励点也增加了解析这些可能性的可能性

123^2
123^-2
123 ^2
123^ 2
123²
123³

我可以做的前四个,但对于后两个,我正在寻找一种将上标替换为数字的方法(我也可以使用str_replace来做,但是我知道这在正则表达式中应该是可能的)。

2 个答案:

答案 0 :(得分:1)

^(?|(\d{1,3}(?=([.,\h])?)(?:\2\d{3})*)(?:(?!\2)[.,](\d*))|(\d+)()(?:[.,](\d*))?|()()[.,](\d+))$

https://regex101.com/r/ZMJEmb/1

整数在组1中。
小数在组3中。

比赛后,第1组中的任何位置都\D全局替换,以去除数千个分隔符。

 ^                             # BOS
 (?|                           # Branch Reset

                                    # Form D,DDD,DDD.dd
      (                             # (1 start), Whole number
           \d{1,3} 
           (?=
                ( [.,\h] )?                   # (2), Thousands seperator
           )
           (?:
                \2 
                \d{3} 
           )*
      )                             # (1 end)
      (?:
           (?! \2 )
           [.,]                          # This form requires at least a fractional separator
           ( \d* )                       # (3), Fractional number, optional
      )
   |  

      ( \d+ )                       # (1), Whole number
      ( )                           # (2), Thousands seperator N/A
      (?:
           [.,] 
           ( \d* )                       # (3), Fractional number, optional
      )?
   |                              # or, Form .dd
      ( )                           # (1), Whole number N/A
      ( )                           # (2), Thousands seperator N/A
      [.,] 
      ( \d+ )                       # (3), Fractional number
 )
 $                             # EOS

答案 1 :(得分:0)

如果要将“ 333.333”视为小数点分隔符,请使用以下方法:

^(\d{0,3}(?=([.,](?!\d+$)| |))(?:\2\d{3})*)(?:[,.](\d*))?$

https://regex101.com/r/TOrxA0/4/

^
  (
    \d{0,3} # Match up to 3 digits so we can...
    (?=([.,](?!\d+$)| |)) # get first separator. Will be used down here:
    (?:\2\d{3})* # get group of 3 digits with previous separator, greedy
  ) # first block
  (?:
      [,.](\d*) # decimal separator + digits
  )? # last block
$

如果要将“ 333.333”视为数字分隔符,请使用:

^(\d{0,3}(?=([ .,]|))(?:\2\d{3})*)(?:[,.](\d*))?$

请参阅:https://regex101.com/r/BsaARo/3/

^
 (
  \d{0,3} # Match up to 3 digits so we can...
  (?=([ .,]|)) # get first separator. Will be used down here:
    (?!\d+$)   # Optional: is just one separator is present, it will be a decimal point
  (?:\2\d{3})* # get group of 3 digits with previous separator, greedy
 ) # First block
 (?:
   [,.](\d*) # decimal separator + digits
 )? # Last block
$ 

编辑:用\ d {3}替换了某些\ d \ d \ d