【问题标题】:gnuplot - convert a string variable to lowercasegnuplot - 将字符串变量转换为小写
【发布时间】:2017-08-21 23:38:43
【问题描述】:

如何在 gnuplot 中将字符串转换为小写?
这是一个 gnuplot 字符串处理问题。

示例:- 我希望在 gnuplot 脚本中检查用户键入的参数....

if (tolower(ARG2) == "ohms") {.....

因此接受“ohms”、“Ohms”或“OHMS”。

首选是不需要使用外部“系统”命令,以便脚本更具可移植性。我目前最好的解决方案是

  arg2 = system("awk 'BEGIN { print toupper(\"".ARG2."\") }'")

然后测试新的字符串变量“arg2”,但是 awk(或其他程序)可能在非 unix 系统上通常不可用,从而使 gnuplot 脚本的可移植性降低。

我看不到任何修改字符串表示形式的增强 gprintf % 格式说明符 - 似乎 gprintf 仅用于转换值。

【问题讨论】:

  • 在我的 Ubuntu 上,awk 无法上/下非 ASCII 字母。您是否尝试检查字符串是否包含 Bash 中的子字符串?
  • arg2=system("${ARG2,,}")
  • 我试图避免系统调用,因此 gnuplot 脚本可能更适合非 unix 系统。在这种情况下,ARG1 是一个数字,ARG2 是可能是 dB 或 Ohms 的单位,所以我需要做不同的绘图数学。无论大小写如何,非 ASCII 都会导致匹配失败,所以我想没问题,因为脚本应该默认为无单位大小写 - 在这种情况下。
  • if [[ ${ARG2,,} == "ohms" ]]; then echo YES; fi 似乎不是 gnuplot 语法 - 我收到一条错误消息 - 期待表达式。

标签: string gnuplot case-conversion


【解决方案1】:

完整的功能宏解决方案(感谢 theozh)让我再次思考如何将其实现为函数。使用查找表通过等同于序数来转换字符的想法是一个好主意。将单个字符大小写转换封装成一个函数是开始,然后与递归一起,它使处理完整字符串成为可能,就像我最初寻找的那样。我希望这对所有人来说都是一个整洁的解决方案。分享和享受。

# GNUPLOT string case conversion
# string_case.gnu   M J Pot, 14/1/2019

# Index lookup table strings
UCases="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
LCases="abcdefghijklmnopqrstuvwxyz"

# Convert a single character
# Char to convert is added to string so it is always found to default other chars
toupperchr(c)=substr( UCases.c, strstrt(LCases.c, c), strstrt(LCases.c, c) )
tolowerchr(c)=substr( LCases.c, strstrt(UCases.c, c), strstrt(UCases.c, c) )

# Convert whole strings
# Conversion first char (or return null), and recurse for the remaining
toupper(s) = s eq ""  ?  ""  :  toupperchr(s[1:1]).toupper(s[2:*])
tolower(s) = s eq ""  ?  ""  :  tolowerchr(s[1:1]).tolower(s[2:*])

补充:改进的解决方案

这是作为自包含函数的递归大小写转换的重新工作。多一点努力解决了第一个解决方案的过多堆栈使用。当我遇到问题时,我只考虑过单个单词的字符串。注意:- 单字符转换更加健壮。

# GNUPLOT string case conversion
# string_case.gnu   M J Pot, 29/1/2019
# toupper(), tolower() functions

# Index lookup table strings
UCases="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
LCases="abcdefghijklmnopqrstuvwxyz"

# Convert a single character
# Char to convert is added to string so it is always found to default other chars
# Null strings are returned null
toupperchr(c)= c eq ""  ?  ""  :  substr( UCases.c, strstrt(LCases.c, c), strstrt(LCases.c, c) )
tolowerchr(c)= c eq ""  ?  ""  :  substr( LCases.c, strstrt(UCases.c, c), strstrt(UCases.c, c) )

# Divide & conquer
# A simple linear recursive call uses too much stack for longer strings.
# This undertakes a binary tree division to make the stack growth order log_2(length)
toupper(s) = strlen(s) <= 1 ? toupperchr(s) : toupper( substr(s,1,strlen(s)/2) ) . toupper( substr(s,(strlen(s)/2)+1,strlen(s)) ) 
tolower(s) = strlen(s) <= 1 ? tolowerchr(s) : tolower( substr(s,1,strlen(s)/2) ) . tolower( substr(s,(strlen(s)/2)+1,strlen(s)) ) 

【讨论】:

  • 太棒了!很高兴,我可以触发接受的解决方案。我忘记了 gnuplot 可以处理递归。但是,nice 递归函数将字符串的最大长度限制为 247 个字符,如果字符串越长,您将收到错误:stack overflow ;-)。好吧,对于大多数情况,247 个字符就足够了。对于(不太方便的)宏解决方案,我没有看到限制,但只测试了最多 10'000 个字符。
  • 根据您的解决方案,我在答案中添加了更简洁的非递归解决方案。
  • 已经用递归解决方案对长字符串问题进行了排序,感谢@theozh让我更多地考虑这个问题。我认为这是现在最好的解决方案。
  • 非常好!似乎不再有“无”字符串长度限制(仅测试最多 100'000 个字符)。对于短字符串长度(
  • 好的,感谢@theozh 的额外测试 - 我只尝试了几千个 :-) 我猜这是现在最好的答案。
【解决方案2】:

我不知道 gnuplot 提供大写或小写功能。 下面的尝试不是一个函数,而是一个宏,它可以将字符串变量w 转换为大写或小写,而无需 OP 所需的外部工具。未在列表中找到的字符保持不变。可能还有改进的余地,但也许它仍然会对某人有所帮助。

### gnuplot implementation of uppercase and lowercase
reset session

Cases= "ABCDEFGHIJKLMNOPQRSTUVWXYZ".\
       "abcdefghijklmnopqrstuvwxyz"

uppercase = 'CaseLen=strlen(Cases)/2;\
    wc = ""; \
    do for [i=1:strlen(w)] { \
        tmp1 = substr(w,i,i); \
        tmp2 = strstrt(Cases,tmp1); \
        wc = (tmp2 == 0) ? wc = wc.tmp1 : \
        (tmp2 > CaseLen) ? (tmp2=tmp2-CaseLen, \
        wc.substr(Cases,tmp2,tmp2)) : wc.substr(Cases,tmp2,tmp2);\
    }; w = wc'

lowercase = 'CaseLen=strlen(Cases)/2;\
    wc = ""; \
    do for [i=1:strlen(w)] { \
        tmp1 = substr(w,i,i); \
        tmp2 = strstrt(Cases,tmp1); \
        wc = (tmp2 == 0) ? wc.tmp1 : \
        (tmp2 < CaseLen) ? (tmp2=tmp2+CaseLen, \
        wc.substr(Cases,tmp2,tmp2)) : wc.substr(Cases,tmp2,tmp2);\
    }; w = wc'

# put your string into variable w
w = "...thE qUick brOWn foX jUmPs oVeR The LazY Dog!"
print w
# run the macro uppercase and variable w will we converted to uppercase
@uppercase
print w

# run the macro lowercase and variable w will we converted to lowercase
@lowercase
print w

### end of code

输出:

...thE qUick brOWn foX jUmPs oVeR The LazY Dog!
...THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG!
...the quick brown fox jumps over the lazy dog!

补充:改进版

我想这就是 SO... 的精神...共同寻找最佳解决方案 :-)。 @mjp,使用您关于在末尾添加字符的好主意以及我“滥用”求和表达式sum 作为循环的“新”想法,从而避免递归。以下解决方案没有递归解决方案具有的字符串的 247 个字符的限制(至少在我的计算机上是 247)。我希望这个解决方案不会有严重的限制。

### gnuplot implementation of uppercase and lowercase
# theozh, 14.01.2019
reset session

UpperCases= "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
LowerCases= "abcdefghijklmnopqrstuvwxyz"

# upper/lowercase for characters
ucchar(c) = substr( UpperCases.c, ucchar_tmp=strstrt(LowerCases.c, c), ucchar_tmp)
lcchar(c) = substr( LowerCases.c, lcchar_tmp=strstrt(UpperCases.c, c), lcchar_tmp)

# upper/lowercase for strings
uc(s) = ((sum[uc_i=1:strlen(s)] (uc_tmp=ucchar(substr(s,uc_i,uc_i)), uc_i>1 ? (uc_w=uc_w.uc_tmp,1):uc_w=uc_tmp,1)),uc_w)
lc(s) = ((sum[lc_i=1:strlen(s)] (lc_tmp=lcchar(substr(s,lc_i,lc_i)), lc_i>1 ? (lc_w=lc_w.lc_tmp,1):lc_w=lc_tmp,1)),lc_w)

s = "...thE qUick brOWn foX jUmPs oVeR The LazY Dog!"
print s
print uc(s)
print lc(s)
### end of code

编辑:(2022 年 1 月) 我再次偶然发现了我的旧帖子,并认为它可以进一步简化。并且更多字符被添加到查找字符串中。

代码:

### uppercase/lowercase function for gnuplot
reset session

UpperCases= "ABCDEFGHIJKLMNOPQRSTUVWXYZÄÁÂÀËÉÊÈÏÍÎÌÖÓÔÒÜÚÛÙŸÝ"
LowerCases= "abcdefghijklmnopqrstuvwxyzäáâàëéêèïíîìöóôòüúûùÿý"

# upper/lowercase for characters
ucc(c) = ((ucc_i=strstrt(LowerCases, c)) ? UpperCases[ucc_i:ucc_i] : c)
lcc(c) = ((lcc_i=strstrt(UpperCases, c)) ? LowerCases[lcc_i:lcc_i] : c)

# upper/lowercase for strings
uc(s) = (uc_s='', sum[uc_i=1:strlen(s)] (uc_s=uc_s.ucc(s[uc_i:uc_i]),1),uc_s)
lc(s) = (lc_s='', sum[lc_i=1:strlen(s)] (lc_s=lc_s.lcc(s[lc_i:lc_i]),1),lc_s)

s = "...thE qUick brOWn foX jUmPs oVeR The LazY Dog!"
print "Input:     ", s
print "Uppercase: ", uc(s)
print "Lowercase: ", lc(s)
### end of code

结果:

Input:     ...thE qUick brOWn foX jUmPs oVeR The LazY Dog!
Uppercase: ...THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG!
Lowercase: ...the quick brown fox jumps over the lazy dog!

【讨论】:

  • 好了,完成了。我确信会有一个非递归的解决方案,但想不出办法。我从未考虑过长字符串(或效率),但 247 有点限制 - 所以我认为使用这种 sum[] 方式是一个更好的通用解决方案。
  • 嗯,与此同时,我发现此解决方案的一个可能(次要)限制是使用变量。这里tmpiw。尽管如您的解决方案所示,可以避免 ucchar(c)lcchar(c) 中的 tmp。在非常不幸的情况下,如果此函数周围的代码使用这些变量之一,则变量将被修改。我不确定如何在函数定义中避免 iw。或者,您必须找到确定在环绕代码中使用的变量名称。或者也许你知道另一种方式?
  • 我试图避免变量 - 重新计算位置参数和递归的美......在这种情况下,我倾向于希望安全并使用以函数名称为前缀的名称,例如“toupper_w”。如果有办法有一个可选的函数参数.....
  • 在“内部”或“本地”变量前加上函数名称是个好主意。这样,代码会更长一些,但变量名冲突不太可能发生。我更改了代码。
【解决方案3】:

当希望将一个不区分大小写的字符串变量与一个已知的字符串常量进行比较时,只需要转换一部分字符。这不是对 gnuplot 中大小写转换的一般情况的回答,但可能适用于许多情况。

arg2 = ARG2
# As we want limited comparisons strstrt(”string”, ”key”) can be used....
# Substitute the first occurrence of a character [pat], with another character [repl]
# Can be used to convert an expected word's case, one character at a time
subchr(src, pat, repl) = strstrt(src, pat)?src[*:strstrt(src, pat)-1].repl.src[strstrt(src, pat)+1:*]:src
arg2 = subchr(arg2, "o", "O")
arg2 = subchr(arg2, "h", "H")
arg2 = subchr(arg2, "m", "M")
arg2 = subchr(arg2, "s", "S")
arg2 = subchr(arg2, "d", "D")
arg2 = subchr(arg2, "b", "B")
if ( arg2[1:2] eq "DB" ) {
  # In terms of dB
  .....
  }
else {
  if ( arg2 eq "OHMS" ) {
    .....
    }
  }

解决方案是编写一个 gnuplot 字符串函数 subchr(),它仅在找到时替换单个匹配字符(三元?),并为每个要转换的字符调用它。幸运的是,gnuplot 字符串范围说明符在 (0) 之前和之后 (stringlength+1) 索引时表现良好,为该区域返回 null。这允许我们返回每个字符升级后的字符串。

这避免了对 awk 等程序的 system() 调用的需要。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-30
    • 2012-03-28
    • 1970-01-01
    • 1970-01-01
    • 2011-08-27
    • 2010-12-04
    相关资源
    最近更新 更多