ubuntu 如何将Perl索引脚本转换为bash函数

55ooxyrt  于 2023-10-17  发布在  Perl
关注(0)|答案(3)|浏览(137)

我想使用perl从bash函数中的any given stringsubstring获取index of

以下是从perl脚本中获取indexOf值的示例:

https://www.geeksforgeeks.org/perl-index-function/

#!/usr/bin/perl
 
# String from which Substring 
# is to be searched 
$string = "Geeks are the best";
 
# Using index() to search for substring
$index = index ($string, 'the');
 
# Printing the position of the substring
print "Position of 'the' in the string: $index\n";

Output:

Position of 'the' in the string: 10

这里是test.sh:

#!/bin/bash

bash_function_get_index_from_perl_script() {
    local index="-1"
    
    # Here is the dummy code 
    # as I don't know how to convert
    # the perl script to bash command lines
    # and get the result from perl script
    
    index="
    
        #!/usr/bin/perl
         
        # String from which Substring 
        # is to be searched 
        $string = "Geeks are the best";
         
        # Using index() to search for substring
        $index = index ($string, 'the');
         
        # Printing the position of the substring
        print "Position of 'the' in the string: $index\n";
    
    "
    
    printf "%s" "$index"
}

result="$(bash_function_get_index_from_perl_script)"

echo "result is: $result"

以下是预期输出:

result is: 10

如何实现“bash_function_get_index_from_perl_script“?

更新:
下面是bash函数测试:

#!/bin/bash

bash_function_get_index() {
    local string="$1"
    local search_string="$2"
    
    before=${string%${search_string}*}
    index=${#before}
    
    printf "%s" "$index"
}

echo "test 1: $(bash_function_get_index "hello world" "wo")"
echo "test 2: $(bash_function_get_index "hello world" "wox")"

下面是输出:

test 1: 6
test 2: 11

“测试2”的结果是错误的,应该是:

test 2: -1

我想在Java中实现相同的“indexOf”函数:

https://www.w3schools.com/java/ref_string_indexof.asp

index_of() {
    local string="$1"
    local search_string="$2"
    local fromIndex="$3"
    
    local index=""
    
    # Get the real index here, the result shoule be the same as the Java's "indexOf"
        
    printf "%s" "$index"
}

更新二:
以下是基于“@F. Hauri - Give Up GitHub“解决方案的测试:

下面的test_example用于获取“if (feature_is_enabled(Feature_111111)) {“和“}“之间的“inner code“。
我使用了第二个变量“hello_world“来获取from_index,以获取“}"的真实的索引。

但是“test_example“没有按预期工作。似乎“indexOf()“功能没有按预期工作。

#!/bin/bash

indexOf() {
    if [[ $1 == -v ]]; then
        local -n _iO_result="$2"
        shift 2
    else
        local _iO_result
    fi
    local _iO_string="$2" _iO_substr="$1" _iO_lhs
    _iO_lhs=${_iO_string%"$_iO_substr"*}
    _iO_result=${#_iO_lhs}
    ((_iO_result == ${#_iO_string} )) && _iO_result=-1
    case ${_iO_result@A} in _iO_result=* ) echo $_iO_result;;esac
}

indexOf_my_params() {
    local string="$1"
    local search_string="$2"
    local from_index="$3"
    
    local offset=-1
    
    if [[ "$from_index" == "" ]]
    then
        offset=0
    else
        if (( $from_index < 0 ))
        then
            from_index=0
        fi
        
        local count=$((${#string} - $from_index))
        if (( $count >= 0 ))
        then
            offset=$from_index
            string="${string:from_index:count}"
        fi
    fi
    
    local index=-1
    
    if [[ "$offset" != "-1" ]]
    then
        index="$(indexOf "$search_string" "$string")"
        
        if (( $index != -1 ))
        then
            index=$(($index + $offset))
        fi
    fi
    
    printf '%s' "$index"
    return "$((index < 0))"
}

test_example() {
    local content="$(cat <<END
initialize(args, hw);
if (feature_is_enabled(Feature_111111)) {
    args.add("foo");
    if(1>2) {
        args.add("test");
    }else{
        args.add("x");
    }
    args.add("hello world");
}

if (feature_is_enabled(Feature_222222)) {
    args.add("bar");
}
END
        )"
        
        local feature_1_if_begin="if (feature_is_enabled(Feature_111111)) {"
        local hello_world="args.add(\"hello world\");"
        local feature_1_if_end="}"
        
        local feature_1_if_begin_index="$(indexOf_my_params "$content" "$feature_1_if_begin")"
        echo "feature_1_if_begin_index: $feature_1_if_begin_index"
        
        local hello_world_index="$(indexOf_my_params "$content" "$hello_world" "$(($feature_1_if_begin_index + ${#feature_1_if_begin}))")"
        echo "hello_world_index: $hello_world_index"
        
        local feature_1_if_end_index="$(indexOf_my_params "$content" "$feature_1_if_end" "$(($hello_world_index + ${#hello_world}))")"
        echo "feature_1_if_end_index: $feature_1_if_end_index"
        
        local feature_1_if_block_code="${content:$(($feature_1_if_begin_index + ${#feature_1_if_begin})):$(($feature_1_if_end_index - $feature_1_if_begin_index - ${#feature_1_if_begin}))}"
        
        echo "------ feature_1_if_block_code (inner code) ------"
        printf "%s\n" "$feature_1_if_block_code"
        
}

test_example
exit 0

实际输出(输出错误):

feature_1_if_begin_index: 22
hello_world_index: 169
feature_1_if_end_index: 260
------ feature_1_if_block_code (inner code) ------

    args.add("foo");
    if(1>2) {
        args.add("test");
    }else{
        args.add("x");
    }
    args.add("hello world");
}

if (feature_is_enabled(Feature_222222)) {
    args.add("bar");

以下是预期输出:

------ feature_1_if_block_code (inner code) ------

    args.add("foo");
    if(1>2) {
        args.add("test");
    }else{
        args.add("x");
    }
    args.add("hello world");

为什么当search keyword是“}“时,“indexOf()“不工作?

UPDATE 3(使用与UPDATE 2相同的“内容”进行测试):

以下是Paul Hodges的解决方案,但仍然没有按预期工作:请注意,我将函数名“index“重命名为“indexof_paul_hodges“。

#!/bin/bash

indexof_paul_hodges ()
{
    local string="$1" key="$2" fromIndex=${3:-0};
    (( fromIndex )) && string=${string:$fromIndex};
    if [[ "$string" =~ "$key" ]]; then
        local ndx="${string%%"$key"*}";
        echo ${#ndx};
    else
        echo "-1";
    fi
}

test_example() {
    local content="$(cat <<END
initialize(args, hw);
if (feature_is_enabled(Feature_111111)) {
    args.add("foo");
    if(1>2) {
        args.add("test");
    }else{
        args.add("x");
    }
    args.add("hello world");
}

if (feature_is_enabled(Feature_222222)) {
    args.add("bar");
}
END
        )"
        
        local feature_1_if_begin="if (feature_is_enabled(Feature_111111)) {"
        local hello_world="args.add(\"hello world\");"
        local feature_1_if_end="}"
        
        local feature_1_if_begin_index="$(indexof_paul_hodges "$content" "$feature_1_if_begin")"
        echo "feature_1_if_begin_index: $feature_1_if_begin_index"
        
        local hello_world_index="$(indexof_paul_hodges "$content" "$hello_world" "$(($feature_1_if_begin_index + ${#feature_1_if_begin}))")"
        echo "hello_world_index: $hello_world_index"
        
        local feature_1_if_end_index="$(indexof_paul_hodges "$content" "$feature_1_if_end" "$(($hello_world_index + ${#hello_world}))")"
        echo "feature_1_if_end_index: $feature_1_if_end_index"
        
        local feature_1_if_block_code="${content:$(($feature_1_if_begin_index + ${#feature_1_if_begin})):$(($feature_1_if_end_index - $feature_1_if_begin_index - ${#feature_1_if_begin}))}"
        
        echo "------ feature_1_if_block_code (inner code) ------"
        printf "%s\n" "$feature_1_if_block_code"
        
}

test_example
exit 0

以下是“indexof_paul_hodges“的输出(结果错误):

feature_1_if_begin_index: 22
hello_world_index: 106
feature_1_if_end_index: 33
------ feature_1_if_block_code (inner code) ------

    args.add("foo");
    if(1>2) {
        args.add("test");
    }else{
        args.add("x");
    }
    args.add("hello world");
}

if (feature_is_enabled(Feature_222

UPDATE 4(使用与UPDATE 2相同的test_example()进行测试):

以下是来自@choroba的解决方案:

#!/bin/bash

bash_function_get_index() {
    local string=$1
    local search=$2
    [[ $string = *"$search"* ]] || { printf %s -1 ; return ; }
    local before=${string%%"$search"*}
    local index=${#before}
    printf %s "$index"
}

indexOf_my_params() {
    local string="$1"
    local search_string="$2"
    local from_index="$3"
    
    local offset=-1
    
    if [[ "$from_index" == "" ]]
    then
        offset=0
    else
        if (( $from_index < 0 ))
        then
            from_index=0
        fi
        
        local count=$((${#string} - $from_index))
        if (( $count >= 0 ))
        then
            offset=$from_index
            string="${string:from_index:count}"
        fi
    fi
    
    local index=-1
    
    if [[ "$offset" != "-1" ]]
    then
        index="$(bash_function_get_index "$string" "$search_string")"
        
        if (( $index != -1 ))
        then
            index=$(($index + $offset))
        fi
    fi
    
    printf '%s' "$index"
    return "$((index < 0))"
}

这里是UPDATE 4的输出(结果是正确的)

feature_1_if_begin_index: 22
hello_world_index: 169
feature_1_if_end_index: 194
------ feature_1_if_block_code (inner code) ------

    args.add("foo");
    if(1>2) {
        args.add("test");
    }else{
        args.add("x");
    }
    args.add("hello world");
4dc9hkyq

4dc9hkyq1#

有很多方法。例如,你可以将脚本发送到perl的标准输入:

#!/bin/bash

bash_function_get_index_from_perl_script() {
    index=$(perl <<- '_PERL_'
    $string = 'Geeks are the best';
    $index = index $string, 'the';
    print "Position of 'the' in the string: $index\n";
    _PERL_
    )
    printf "%s" "$index"
}

result=$(bash_function_get_index_from_perl_script)

echo "result is: $result"

但是你不需要Perl来做这件事,你可以在bash本身中使用参数扩展来找到位置:

#!/bin/bash

bash_function_get_index() {
    string=$1
    search=$2
    [[ $string = *"$search"* ]] || { printf %s -1 ; return ; }
    before=${string%%"$search"*}
    index=${#before}
    printf %s "$index"
}

for s in the thex ; do
    result=$(bash_function_get_index 'Geeks are the best' "$s")
    echo "Position of '$s' in the string: $result"
done

若要包含起始位置,只需在尝试匹配子字符串之前从字符串中删除起始位置之前的所有内容。不要忘记将起始位置添加到结果中:

bash_function_get_index() {
    string=$1
    search=$2
    pos=${3:-0}
    string=${string:$pos}
    [[ $string = *"$search"* ]] || { printf %s -1 ; return ; }
    before=${string%%"$search"*}
    index=${#before}
    printf %s $(( pos + index ))
}
8tntrjer

8tntrjer2#

bashstringsubstring 的索引

试试这个:

string="Geeks are the best"
sub=the
lhs=${string%"$sub"*}
echo ${#lhs}
10

作为函数

使用-v选项来分配变量而不是回显。为了避免无用的叉子:

indexOf() {
    if [[ $1 == -v ]]; then
        local -n _iO_result="$2"
        shift 2
    else
        local _iO_result
    fi
    local _iO_string="$2" _iO_substr="$1" _iO_lhs
    _iO_lhs=${_iO_string%"$_iO_substr"*}
    _iO_result=${#_iO_lhs}
    ((_iO_result == ${#_iO_string} )) && _iO_result=-1
    case ${_iO_result@A} in _iO_result=* ) echo "$_iO_result";;esac
}

一个例外:如果未找到 substring,则答案为-1

测试和语法

然后

indexOf the "Geeks are the best"
10

indexOf -v var the "Geeks are the best"
echo $var
10

indexOf bad "Hello good world!"
-1

indexOf '*' 'abc*efg???x'
3

然后为了避免分叉var=$(function...),使用-v var选项!!

tcnt=1;for tests in  $'wo\thello world' $'wox\thello world' $'*\tabc*efg???x'; do
    tststr=${tests%%$'\t'*} string=${tests#*$'\t'}
    indexOf -v idx "$tststr" "$string"
    printf 'Test %2d: result: %3d. string "%s" substring: "%s"\n' \
        $((tcnt++)) "$idx" "$string" "$tststr"
done

应产生:

Test  1: result:   6. string "hello world" substring: "wo"
Test  2: result:  -1. string "hello world" substring: "wox"
Test  3: result:   3. string "abc*efg???x" substring: "*"

为什么我坚持 * 避免分叉 *

试着运行1 '000次作业:

time for ((i=1000;i--;)){ idx=$(indexOf 'wo' 'Hello world') ;};echo $idx
real    0m0.948s
user    0m0.608s
sys     0m0.337s
6
time for ((i=1000;i--;)){ indexOf -v idx 'wo' 'Hello world' ;};echo $idx
real    0m0.030s
user    0m0.030s
sys     0m0.000s
6

从大约1秒到大约3100秒!!
无可奉告!

carvr3hs

carvr3hs3#

我不认为这是做什么显着不同,从别人做什么,但实现了你所要求的与本机内置的语法,也许是一个更容易阅读?

$: declare -f index
index ()
{
    local string="$1" key="$2" fromIndex=${3:-0};
    (( fromIndex )) && string=${string:$fromIndex};
    if [[ "$string" =~ "$key" ]]; then
        local ndx="${string%%"$key"*}";
        echo ${#ndx};
    else
        echo "-1";
    fi
}

$: index "Geeks are the best" the
10

$: index "Geeks are the best" the 4
6

$: index "Geeks are the best" the 12
-1

$: index "Geeks are the best" foo
-1

编辑

这有点像一个XY Problem和一个可怕的脆弱的Y。你到底想完成什么?
一般来说,除非你是完全完全控制和唯一控制代码的(甚至可能不是这样),否则不要试图以这种方式解析代码。一个小的“无害”更改现在会破坏您的解析。
即便如此,您的问题是您使用的偏移量并不是从同一个地方开始计数的。你必须从源字符串的开头开始索引,即使你必须在中间使用一个点来识别正确的右括号.这就是为什么它如此脆弱。

$: cat tst
#!/bin/bash
indexof_paul_hodges () { local string="$1" key="$2" fromIndex=${3:-0};
    (( fromIndex )) && string=${string:$fromIndex};
    if [[ "$string" =~ "$key" ]]
    then local ndx="${string%%"$key"*}";
         echo ${#ndx};
    else echo "-1"; # this should probably be "return 1"
    fi
}
test_example() { local content="$1"
  local -i if_begin_index if_begin_end hello_world_index hello_world_end if_end_index
  local if_begin=$'if (feature_is_enabled(Feature_111111)) {' hello_world=$'args.add("hello world");' if_end="}"
  if_begin_index="$(indexof_paul_hodges "$content" "$if_begin")"
  if_begin_end=if_begin_index+${#if_begin}
  hello_world_index="$( indexof_paul_hodges "$content" "$hello_world" )"                      # index FROM START
  hello_world_end=hello_world_index+${#hello_world}
  if_end_index=$(indexof_paul_hodges "$content" "$if_end" "$hello_world_end")+hello_world_end # index FROM START
  local if_block="${content:$if_begin_index:$if_end_index - $if_begin_index + 1}"             # include all
  local if_content="${content:$if_begin_end:$if_end_index - $if_begin_end}"                   # inside braces only
  printf "%s\n" "--- if block ---" "$if_block" "" "--- inner code ---"  "$if_content"
}
content='
    initialize(args, hw);
    if (feature_is_enabled(Feature_111111)) { /* comments can show up anywhere */
      if(1>2) { args.add("test"); } else { args.add("x"); }
      args.add("hello world"); /* comments can include braces... */
    }
    if (feature_is_enabled(Feature_222222)) { args.add("bar"); }
  '
echo "As-is:";                 test_example "$content"
echo "with a comment edited:"; test_example "${content/braces/\}}"

运行时:

$: ./tst
As-is:
--- if block ---
if (feature_is_enabled(Feature_111111)) { /* comments can show up anywhere */
      if(1>2) { args.add("test"); } else { args.add("x"); }
      args.add("hello world"); /* comments can include braces... */
    }

--- inner code ---
 /* comments can show up anywhere */
      if(1>2) { args.add("test"); } else { args.add("x"); }
      args.add("hello world"); /* comments can include braces... */

with a comment edited:
--- if block ---
if (feature_is_enabled(Feature_111111)) { /* comments can show up anywhere */
      if(1>2) { args.add("test"); } else { args.add("x"); }
      args.add("hello world"); /* comments can include }

--- inner code ---
 /* comments can show up anywhere */
      if(1>2) { args.add("test"); } else { args.add("x"); }
      args.add("hello world"); /* comments can include

再问一遍:你实际上想完成什么?

相关问题