gnuplot - convert a string variable to lowercase

牧云@^-^@ 提交于 2021-02-19 05:19:33

问题


How do you convert a string to lowercase in gnuplot?
This is a gnuplot string handling question.

Example:- I wish to check a user typed parameter in a gnuplot script....

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

so by accepting "ohms", "Ohms", or "OHMS".

The preference is to not need to use an external "system" command so that the script is more portable. My current best solution is

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

and then test the new string variable "arg2", but awk (or other program) may not be generally available on a non unix system, making the gnuplot script less portable.

I cannot see any enhanced gprintf % format specifiers that modifies string presentation - it seems gprintf is only for converting values.


回答1:


I am not aware that gnuplot offers uppercase or lowercase functions. The attempt below is not a function but a macro which converts the string variable w into uppercase or lowercase without external tools as desired from the OP. Characters which are not found in the list are kept unchanged. There is probably room for improvement, but maybe it will still be helpful to somebody.

### 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

Output:

...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!

Addition: improved version

I guess that's the spirit of SO... together find the best solutions :-). @mjp, using your nice idea about adding the character at the end and my "new" idea of "misusing" the summation expression sum as a loop, thus avoiding recursion. The follwing solution does not have the limit of 247 characters for the string which the recursive solution has (at least on my computer it was 247). I hope there will be no severe limitations in this solution.

### gnuplot implementation of uppercase and lowercase
# theozh, 14.01.2014
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



回答2:


The full function Macro solution (Thanks theozh) has me thinking again of how to implement this as a function. The idea of using a lookup table to convert characters by equating an ordinal number was a great idea. Encapsulating single character case conversion into a function was the start, and then along with recursion, it has made it possible to handle full strings as I had first looked for. I hope this is now a tidy solution for all. Share and enjoy.

# 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:*])

Addition: Improved solution

This is a re-work of the recursive case conversion as self contained functions. A little more effort has resolved the excessive stack usage of the first solution. I had only been considering strings of single words when I had the problem. Note:- the single character conversion has been made more robust.

# 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)) ) 



回答3:


When wishing to compare a string variable independent of case to a known string constant, only a subset of characters need to be converted. This is not an answer to the general situation of case conversion in gnuplot, but may work for many situations.

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" ) {
    .....
    }
  }

The solution is to write a gnuplot string function subchr() which replaces a single matching character, only if found (the ternary ?), and to call it for each of the characters to be converted. Fortunately, gnuplot string range specifiers appear well behaved when indexing before (0) and beyond (stringlength+1), returning null for that region. This allows us to return the string with each character upgraded.

This avoids the need for a system() call to a program like awk, etc.



来源:https://stackoverflow.com/questions/45806917/gnuplot-convert-a-string-variable-to-lowercase

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!