Regex 查找第一个非零小数点的位置

Regex 查找第一个非零小数点的位置,regex,string,stata,Regex,String,Stata,假设我有以下本地宏: loc a = 12.000923 我想得到第一个非零小数点的小数位置(4) 实现这一点的方法有很多。一种是将a视为字符串,并找到的位置: loc a = 12.000923 loc b = strpos(string(`a'), ".") di "`b'" . mata: : k = selectindex(a :== ".") + 1 : k 3 : end 从这里可以进一步循环小数并计数,因为我得到了第一个非零元素。当然,这似乎不是一个非常优雅的方法

假设我有以下本地宏:

loc a = 12.000923
我想得到第一个非零小数点的小数位置(
4

实现这一点的方法有很多。一种是将
a
视为字符串,并找到
的位置:

loc a = 12.000923
loc b = strpos(string(`a'), ".")
di "`b'"
. mata: 

: k = selectindex(a :== ".") + 1

: k
  3

: end
从这里可以进一步循环小数并计数,因为我得到了第一个非零元素。当然,这似乎不是一个非常优雅的方法


你能建议一个更好的方法来处理这个问题吗?正则表达式也许?

嗯,我不知道Stata,但是根据支持的代码,
\(0+)
,在Stata中转换这两行JavaScript函数应该不难

它返回第一个非零小数点的位置,如果没有小数点,则返回-1

function getNonZeroDecimalPosition(v) {
  var v2 = v.replace(/\.(0+)?/, "")
  return v2.length !== v.length ? v.length - v2.length : -1
}
解释

我们从输入字符串中删除一个点,后跟可选的连续零。 原始输入字符串和新字符串的长度之差给出了第一个非零小数点的位置

示例片段

函数getNonZeroDecimalPosition(v){ var v2=v.replace(/\(0+)/,“”) 返回v2.length!==v.length?v.length-v2.length:-1 } 变量样本=[ “loc a=12.00012”, “loc b=12”, “loc c=12.012”, “loc d=1.000012”, “loc e=-10.00012”, “loc f=-10.05012”, “loc g=0.0012” ] samples.forEach(函数(示例){ console.log(getNonZeroDecimalPosition(示例))
})好吧,我不知道Stata,但是根据支持的文件,
\.(0+)
应该不难在Stata中转换这两行JavaScript函数

它返回第一个非零小数点的位置,如果没有小数点,则返回-1

function getNonZeroDecimalPosition(v) {
  var v2 = v.replace(/\.(0+)?/, "")
  return v2.length !== v.length ? v.length - v2.length : -1
}
解释

我们从输入字符串中删除一个点,后跟可选的连续零。 原始输入字符串和新字符串的长度之差给出了第一个非零小数点的位置

示例片段

函数getNonZeroDecimalPosition(v){ var v2=v.replace(/\(0+)/,“”) 返回v2.length!==v.length?v.length-v2.length:-1 } 变量样本=[ “loc a=12.00012”, “loc b=12”, “loc c=12.012”, “loc d=1.000012”, “loc e=-10.00012”, “loc f=-10.05012”, “loc g=0.0012” ] samples.forEach(函数(示例){ console.log(getNonZeroDecimalPosition(示例))
})简单的回答使用正则表达式和命令处理字符串。 可以选择所有小数,找到第一个非0小数,最后找到其位置:

loc v  = "123.000923"

loc v2 = regexr("`v'", "^[0-9]*[/.]", "")      // 000923
loc v3 = regexr("`v'", "^[0-9]*[/.][0]*", "")  // 923
loc first = substr("`v3'", 1, 1)               // 9
loc first_pos = strpos("`v2'", "`first'")      // 4: position of 9 in 000923

di "`v2'"
di "`v3'"
di "`first'" 
di "`first_pos'" 
在一个步骤中相当于:

loc first_pos2 = strpos(regexr("`v'", "^[0-9]*[/.]", ""), substr(regexr("`v'", "^[0-9]*[/.][0]*", ""), 1, 1))
di "`first_pos2'"
另一个答案中建议的另一种方法是比较从0清除的小数块的长度与未清除的小数块的长度。 其中一个步骤是:

 loc first_pos3 = strlen(regexr("`v'", "^[0-9]*[/.]", "")) - strlen(regexr("`v'", "^[0-9]*[/.][0]*", "")) + 1
 di "`first_pos3'" 

straighforward答案使用正则表达式和命令处理字符串。 可以选择所有小数,找到第一个非0小数,最后找到其位置:

loc v  = "123.000923"

loc v2 = regexr("`v'", "^[0-9]*[/.]", "")      // 000923
loc v3 = regexr("`v'", "^[0-9]*[/.][0]*", "")  // 923
loc first = substr("`v3'", 1, 1)               // 9
loc first_pos = strpos("`v2'", "`first'")      // 4: position of 9 in 000923

di "`v2'"
di "`v3'"
di "`first'" 
di "`first_pos'" 
在一个步骤中相当于:

loc first_pos2 = strpos(regexr("`v'", "^[0-9]*[/.]", ""), substr(regexr("`v'", "^[0-9]*[/.][0]*", ""), 1, 1))
di "`first_pos2'"
另一个答案中建议的另一种方法是比较从0清除的小数块的长度与未清除的小数块的长度。 其中一个步骤是:

 loc first_pos3 = strlen(regexr("`v'", "^[0-9]*[/.]", "")) - strlen(regexr("`v'", "^[0-9]*[/.][0]*", "")) + 1
 di "`first_pos3'" 

您可以在
mata
中的一行中执行此操作,而无需使用正则表达式:

foreach x in 124.000923 65.020923 1.000022030 0.0090843 .00000425 {
    mata: selectindex(tokens(tokens(st_local("x"), ".")[selectindex(tokens(st_local("x"), ".") :== ".") + 1], "0") :!= "0")[1]
}

4
2
5
3
6
在下面,您可以看到详细的步骤:

. local x = 124.000823

. mata:

: /* Step 1: break Stata's local macro x in tokens using . as a parsing char */
: a = tokens(st_local("x"), ".")

: a
            1        2        3
    +----------------------------+
  1 |     124        .   000823  |
    +----------------------------+

: /* Step 2: tokenize the string in a[1,3] using 0 as a parsing char */
: b = tokens(a[3], "0")

: b
         1     2     3     4
    +-------------------------+
  1 |    0     0     0   823  |
    +-------------------------+

: /* Step 3: find which values are different from zero */
: c = b :!= "0"

: c
       1   2   3   4
    +-----------------+
  1 |  0   0   0   1  |
    +-----------------+

: /* Step 4: find the first index position where this is true */
: d = selectindex(c :!= 0)[1]

: d
  4

: end
您还可以在步骤
2
中使用 同样的逻辑

这是
的索引值之后的索引值:

loc a = 12.000923
loc b = strpos(string(`a'), ".")
di "`b'"
. mata: 

: k = selectindex(a :== ".") + 1

: k
  3

: end
在这种情况下,步骤
2
变为:

. mata: 

: 
: b = tokens(a[k], "0")

: b
         1     2     3     4
    +-------------------------+
  1 |    0     0     0   823  |
    +-------------------------+

: end
对于不带小数的意外情况:

foreach x in 124.000923 65.020923 1.000022030 12 0.0090843 .00000425 {
    if strmatch("`x'", "*.*") mata: selectindex(tokens(tokens(st_local("x"), ".")[selectindex(tokens(st_local("x"), ".") :== ".") + 1], "0") :!= "0")[1]
    else display "  0"
}

4
2
5
0
3
6

您可以在
mata
中的一行中执行此操作,而无需使用正则表达式:

foreach x in 124.000923 65.020923 1.000022030 0.0090843 .00000425 {
    mata: selectindex(tokens(tokens(st_local("x"), ".")[selectindex(tokens(st_local("x"), ".") :== ".") + 1], "0") :!= "0")[1]
}

4
2
5
3
6
在下面,您可以看到详细的步骤:

. local x = 124.000823

. mata:

: /* Step 1: break Stata's local macro x in tokens using . as a parsing char */
: a = tokens(st_local("x"), ".")

: a
            1        2        3
    +----------------------------+
  1 |     124        .   000823  |
    +----------------------------+

: /* Step 2: tokenize the string in a[1,3] using 0 as a parsing char */
: b = tokens(a[3], "0")

: b
         1     2     3     4
    +-------------------------+
  1 |    0     0     0   823  |
    +-------------------------+

: /* Step 3: find which values are different from zero */
: c = b :!= "0"

: c
       1   2   3   4
    +-----------------+
  1 |  0   0   0   1  |
    +-----------------+

: /* Step 4: find the first index position where this is true */
: d = selectindex(c :!= 0)[1]

: d
  4

: end
您还可以在步骤
2
中使用 同样的逻辑

这是
的索引值之后的索引值:

loc a = 12.000923
loc b = strpos(string(`a'), ".")
di "`b'"
. mata: 

: k = selectindex(a :== ".") + 1

: k
  3

: end
在这种情况下,步骤
2
变为:

. mata: 

: 
: b = tokens(a[k], "0")

: b
         1     2     3     4
    +-------------------------+
  1 |    0     0     0   823  |
    +-------------------------+

: end
对于不带小数的意外情况:

foreach x in 124.000923 65.020923 1.000022030 12 0.0090843 .00000425 {
    if strmatch("`x'", "*.*") mata: selectindex(tokens(tokens(st_local("x"), ".")[selectindex(tokens(st_local("x"), ".") :== ".") + 1], "0") :!= "0")[1]
    else display "  0"
}

4
2
5
0
3
6

珠光的Mata解决方案非常讨人喜欢,但对于“完全没有小数点”的“意外”情况,应予以注意

此外,当正则表达式可以在令人难忘的1行中创建时,它也不是一个太坏的选择

loc v  = "123.000923"
capture local x = regexm("`v'","(\.0*)")*length(regexs(0))
下面的代码使用更多的v值进行测试

foreach v in 124.000923 605.20923 1.10022030 0.0090843 .00000425 12 .000125 {
capture local x = regexm("`v'","(\.0*)")*length(regexs(0))
di "`v': The wanted number = `x'"
}

珠光的Mata解决方案非常讨人喜欢,但对于“完全没有小数点”的“意外”情况,应予以注意

此外,当正则表达式可以在令人难忘的1行中创建时,它也不是一个太坏的选择

loc v  = "123.000923"
capture local x = regexm("`v'","(\.0*)")*length(regexs(0))
下面的代码使用更多的v值进行测试

foreach v in 124.000923 605.20923 1.10022030 0.0090843 .00000425 12 .000125 {
capture local x = regexm("`v'","(\.0*)")*length(regexs(0))
di "`v': The wanted number = `x'"
}

不使用regex,而是使用log10(将数字视为数字),此函数将:

  • 对于大于等于1的数字或{ dFD=Math.log10(Math.abs(n))| 0; 如果(n>=1 | | n{ log(`${element},十进制中的数字:${digitsFromDecimal(element)}`); }); //输出 //118.816133,小数点后的数字:3 //11.1050166,小数位数:2 //9.254180571,小数位数:1 //-1.245501523,小数位数:1 //1,小数位数:1 //0,小数点后的数字:0 //0.864931613,小数位数:0 //0.097007836,小数位数:-1 //-0.010880074,小数点后的数字:-1 //0.009066729,小数点后的数字:-2
    不使用regex,而是使用log10(将数字视为数字),此函数将:

    • 对于大于等于1的数字或{ dFD=Math.log10(Math.abs(n))| 0; 如果(n>=1 | | n{ log(`${element},十进制中的数字:${digitsFromDecimal(element)}`); }); //输出 //118.816133,小数点后的数字:3 //11.1050166,小数位数:2 //9.254180571,小数位数:1 //-1.245501523,小数位数:1 //1,小数位数:1 //0,小数点后的数字:0 //0.864931613,小数位数:0 //0.097007836,小数位数:-1 //-0.010880074,小数点后的数字:-1 //