Calculadora AppleScript: pegue a equação de texto selecionada e calcule o resultado

2

Desejo criar um Serviço capaz de pegar o texto selecionado, executar automaticamente a operação matemática desejada e colar o resultado diretamente após o texto selecionado. Este serviço é semelhante à função de calculadora integrada da Pesquisa do Google, mas é mais útil.

aqui estão alguns exemplos:

se este for o texto selecionado : esse é um novo texto

43 + 957: = 1000

763-9482: = -8719

8 * 26: = 208

83/23: = 3.60869565217

As operações acima incluem adição, subtração, multiplicação e divisão. Até agora, esse script não é difícil de escrever.

Mas também gostaria da capacidade de usar parênteses nos cálculos. É aqui que a estrada fica rochosa.

Aqui estão alguns exemplos de equações que envolvem parênteses:

(4 + 55) / 2: = 29,5

352 + ((76.031 * 57/100) + (93.6 * 87/100)): = 476.76967

(45 + 36 + (64 * 0,04) + 152 + 33 + 90) * (1 / (1,98-425- (0,25 * 629) +431)): = -2.40209017217

Caramba.

OK. Passos de bebê...

Aqui está o código que eu escrevi. Ele pode lidar apenas com o primeiro conjunto de exemplos:

set inputString to "43 + 555 /4 *122"

-- Remove any and all spaces from this string
set inputString to replace_chars(inputString, " ", "")

-- Convert every instance of "x" to "*"
if (inputString contains "x") then
    set inputString to replace_chars(inputString, "x", "*")
end if

-- Ensure that the string contains no foreign characters:
set supportedCharacters to {"1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "+", "-", "*", "/"}

set x to 1
set everyCharacterInInputStringIsValid to true

repeat until (x > (length of inputString))
    if supportedCharacters contains (character x of inputString) then
        set x to (x + 1)
    else
        set everyCharacterInInputStringIsValid to false
        display dialog "Input string contains invalid character: " & (character x of inputString)
        error number -128 (* user cancelled *)
    end if
end repeat

-- String is all good. Now for the "fun" part.

set AppleScript's text item delimiters to {"+", "-", "*", "/"}
set onlyTheNumbers to text items of inputString
set AppleScript's text item delimiters to {""}
-- return onlyTheNumbers -- {"43", "555", "4", "122"}

set AppleScript's text item delimiters to onlyTheNumbers
set onlyTheSymbols to text items of inputString
set AppleScript's text item delimiters to {""}
-- return onlyTheSymbols -- {"", "+", "/", "*", ""}

-- Remove the first and last items in the onlyTheSymbols list
-- post #3 from http://macscripter.net/viewtopic.php?id=43371/
set removeSpecificItemsFromList to {1, (count of onlyTheSymbols)}
repeat with i in removeSpecificItemsFromList
    set item i of onlyTheSymbols to null
end repeat
set onlyTheSymbols to every text of onlyTheSymbols

set calculatorBalance to ((0) as number)
set x to 1 as integer
set y to 2 as integer
set z to 1 as integer
set num1 to (((item x) of onlyTheNumbers) as number)
repeat until ((z) is greater than (count of onlyTheSymbols))

    set num2 to (((item (y)) of onlyTheNumbers) as number)
    set symbol to ((item z) of onlyTheSymbols)
    if (symbol is "+") then
        set calculatorBalance to (num1 + num2)
    else if (symbol is "-") then
        set calculatorBalance to (num1 - num2)
    else if (symbol is "*") then
        set calculatorBalance to (num1 * num2)
    else if (symbol is "/") then
        set calculatorBalance to (num1 / num2)
    end if

    set num1 to (calculatorBalance as number)

    set y to (y + 1)
    set z to (z + 1)
end repeat

display dialog " = " & calculatorBalance


on replace_chars(this_text, search_string, replacement_string)
    set AppleScript's text item delimiters to the search_string
    set the item_list to every text item of this_text
    set AppleScript's text item delimiters to the replacement_string
    set this_text to the item_list as string
    set AppleScript's text item delimiters to ""
    return this_text
end replace_chars

Estou confuso sobre como abordar todo o conceito de parênteses neste script. Alguém pode ajudar?

Aqui está minha ideia aproximada:

  1. Determine quantos parênteses estão na sequência.

  2. Divida a sequência de entrada em segmentos. O número de segmentos é baseado no número total de parênteses na sequência, menos um. O número de segmentos deve ser um número ímpar.

  3. Verifique se algum dos segmentos contém parênteses incorporados.

  4. Repita as etapas de 1 a 4 até que não haja parênteses em nenhum segmento.

  5. Agora que você tem seus segmentos, aja como se cada segmento fosse sua própria sequência. Ou seja, calcule o resultado de cada segmento independentemente, em vez de simplesmente usar o número anterior na lista para interagir com o número a seguir na lista.

  6. Adicione todos os resultados do segmento.

Não tenho certeza se tenho a ideia certa.

Estou ciente de que ignorei completamente o conceito de ordem das operações . Também não sei como implementar isso exatamente. Minha defesa é que isso é basicamente parte do código de parênteses. Por exemplo, 1 + 4 * 2 deveria primeiro ser convertido em 1+ (4 * 2) antes que o resultado pudesse ser calculado.


Nota:

Afirmei que desejo que a entrada para o AppleScript seja o texto atualmente selecionado. Mas você verá claramente que não escrevi o código dessa maneira.

Para escrever, depurar e solucionar problemas desse script, estou ignorando esse elemento do script, porque essa é uma parte muito fácil de escrever e torna o teste do código mais complicado.

Depois que o script for aperfeiçoado, simplesmente configurarei o Serviço para receber selected text in any application. Para a saída, vou dizer ao script para codificar o código e colar o resultado final.


A propósito, se essas perguntas elaboradas sobre AppleScript estão exagerando no Ask Different , informe-me e eu as levarei para um site mais centralizado em AppleScript (por exemplo, MacScripter.net). Não sei se estou pressionando meu limite aqui.

esfera de rubik
fonte
O tópico principal aqui é encontrar uma maneira de analisar fórmulas correta e eficientemente. O AppleScript é apenas uma ferramenta para fazer isso (provavelmente não é o melhor, mas tem tudo o que é necessário).
nohillside
Este é um exercício acadêmico para aprender mais sobre o AppleScript ou você precisa criar este serviço para uso prático?
Graham Miln
@GrahamMiln Não é um exercício acadêmico. Quero realmente usar este AppleScript como minha calculadora básica.
Rubik's sphere
Por favor, você pode afinar sua pergunta. É improvável que um analisador completo em uma pergunta atraia boas respostas. Em vez disso, pergunte sobre como iterar os caracteres, manter uma pilha de colchetes de abertura e fechamento ou outros problemas mais específicos que você estiver enfrentando. Cada um pode ser respondido individualmente e pode ser mais útil para muitos que aprendem AppleScript.
Graham Miln
1
O stackoverflow.com/questions/28256/… fornece uma boa visão das opções de design disponíveis - independentemente da linguagem de implementação.
Graham Miln

Respostas:

3

No StackOverflow, você encontrará estas perguntas relacionadas:

Para uma discussão sobre a análise de expressões, consulte:

O ônus do AppleScript

AppleScript não é uma linguagem para se apreciar escrever um analisador. A linguagem é ótima para muitas coisas, mas não para manipulação de texto. A linguagem é Turing Complete , portanto seu projeto é possível, mas difícil.

AppleScript é um dialeto Open Scripting Architecture (OSA) e talvez você queira considerar outro dialeto OSA para este projeto, como JavaScript. Embora o JavaScript não seja o ideal, você encontrará mais recursos e guias para ajudá-lo. Você também pode misturar e combinar scripts AppleScript e JavaScript compilados pelo Editor de Script.

Usar bc

Considere canalizar o texto selecionado bce retornar o resultado:

set theInput to "(4.0+55.0)/2.0"
set myCalculation to "echo 'scale=1;" & (theInput) & "' | bc"
set myResult to do shell script myCalculation

Essa abordagem evita reinventar a roda e usa a calculadora de linha de comando incluída no macOS bc,.

Graham Miln
fonte
Uau, isso é útil. Sou grato por você ter me apresentado bc, pois usá-lo simplifica drasticamente meu código. Você avisou que talvez eu não atraísse boas respostas ... Eu consideraria essa uma resposta muito boa!
esfera de Rubik