假设我有以下本地宏:
loc a = 12.000923
我想获得第一个非零小数的小数位置(在此示例中4
(。
有很多方法可以实现这一目标。一种是将a
视为字符串,并找到.
的位置:
loc a = 12.000923
loc b = strpos(string(`a'), ".")
di "`b'"
从这里可以进一步循环穿过小数和计数,因为我得到了第一个非零元素。当然,这似乎不是一种非常优雅的方法。
您能提出一种更好的方法来解决这个问题吗?正则表达式可能?
好吧,我不知道Stata,但是根据文档,.(0+)?
已被调用,在Stata中转换这2行JavaScript功能并不难。
如果没有十进制,它将返回第一个非零十进制的位置或-1。
function getNonZeroDecimalPosition(v) {
var v2 = v.replace(/.(0+)?/, "")
return v2.length !== v.length ? v.length - v2.length : -1
}
说明
我们从输入字符串中删除一个点,然后是可选的连续零。 原始输入字符串的长度和此新字符串的差异给出了第一个非零十进制的位置
演示
样本摘要
function getNonZeroDecimalPosition(v) {
var v2 = v.replace(/.(0+)?/, "")
return v2.length !== v.length ? v.length - v2.length : -1
}
var samples = [
"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(function(sample) {
console.log(getNonZeroDecimalPosition(sample))
})
您可以在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
中找到了感兴趣的字符串的位置相同的逻辑。
这是.
之后的索引值:
. 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
不使用REGEX,而是Log10(将数字视为数字(,此功能将:
- 对于数字> = 1或数字< = -1,用正数返回小数的左数。
- 或(更具体地说是您要问的(,对于1到-1之间的数字,用负数返回,数字是第一个非零数字发生的小数右侧的数字。
digitsFromDecimal = (n) => {
dFD = Math.log10(Math.abs(n)) | 0;
if (n >= 1 || n <= -1) { dFD++; }
return dFD;
}
var x = [118.8161330, 11.10501660, 9.254180571, -1.245501523, 1, 0, 0.864931613, 0.097007836, -0.010880074, 0.009066729];
x.forEach(element => {
console.log(`${element}, Digits from Decimal: ${digitsFromDecimal(element)}`);
});
// Output
// 118.816133, Digits from Decimal: 3
// 11.1050166, Digits from Decimal: 2
// 9.254180571, Digits from Decimal: 1
// -1.245501523, Digits from Decimal: 1
// 1, Digits from Decimal: 1
// 0, Digits from Decimal: 0
// 0.864931613, Digits from Decimal: 0
// 0.097007836, Digits from Decimal: -1
// -0.010880074, Digits from Decimal: -1
// 0.009066729, Digits from Decimal: -2
直截了当的答案使用正则表达式和命令与字符串一起使用。一个人可以选择所有小数,找到第一个非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'"
另一种答案中建议的一种替代方法是比较从0s清除的小数块的lenght与未清洁的小数块。在一个步骤中,这是:
loc first_pos3 = strlen(regexr("`v'", "^[0-9]*[/.]", "")) - strlen(regexr("`v'", "^[0-9]*[/.][0]*", "")) + 1
di "`first_pos3'"
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'"
}