एक चर का नाम प्रिंट करें [बंद]


20

एक फ़ंक्शन (पूर्ण प्रोग्राम नहीं) लिखें, ताकि यदि फ़ंक्शन को एक एकल वैश्विक चर (या आपकी भाषा के निकटतम समतुल्य) के साथ इसके तर्क के रूप में कहा जाए, तो यह उस चर का नाम आउटपुट (यानी प्रिंट या रिटर्न) करता है। यदि तर्क एक चर नहीं है, तो इसके बजाय एक गलत मूल्य का उत्पादन करें। (आपको उस मामले को संभालने की ज़रूरत नहीं है जहाँ तर्क एक चर है, लेकिन वैश्विक नहीं है।)

फ़ंक्शन कॉल और फ़ंक्शन परिभाषा के बीच एक संकलन-समय कनेक्शन नहीं होना चाहिए (विशेष रूप से, फ़ंक्शन परिभाषा एक मैक्रो या समान निर्माण नहीं हो सकती है जो स्रोत कोड के शाब्दिक टुकड़े के रूप में तर्क प्राप्त करती है, न तो पाठ में और न ही सार सिंटैक्स ट्री में प्रपत्र)। वह यह है: ऐसी भाषाएं जो अलग संकलन का समर्थन करती हैं, प्रोग्राम को काम करना चाहिए भले ही फ़ंक्शन कॉल पहले संकलित हो (फ़ंक्शन परिभाषा का ज्ञान नहीं है, लेकिन संभवतः एक प्रकार का हस्ताक्षर या समकक्ष), फिर फ़ंक्शन परिभाषा बाद में संकलित की जाती है। यदि भाषा में अलग संकलन नहीं है, तो आपको कॉल और परिभाषा के बीच समान अलगाव के लिए लक्ष्य बनाना होगा।

यदि संकलित भाषा का उपयोग कर रहे हैं, तो आप डिस्क से पूर्ण प्रोग्राम का संकलित रूप पढ़ सकते हैं, और मान सकते हैं कि प्रोग्राम डिबग जानकारी के साथ संकलित किया गया था। (इस प्रकार, एक प्रोग्राम से डिबगर को संलग्न करके काम करने वाले समाधानों की अनुमति है।)

ध्यान दें कि यह कार्य हर भाषा में संभव नहीं हो सकता है।

उदाहरण:

var apple = "Hello"
p(apple) // apple

var nil = "Nothing"
p(nil) // nil

var SOMETHING = 69
p(SOMETHING) // SOMETHING

function foo(){}
p(foo) // foo

p(3.14159) // false

p(function foo(){}) // false

टिप्पणियाँ विस्तारित चर्चा के लिए नहीं हैं; इस वार्तालाप को बातचीत में स्थानांतरित कर दिया गया है ।
डेनिस

जवाबों:


31

जावा

String getParamName(String param) throws Exception {
    StackTraceElement[] strace = new Exception().getStackTrace();
    String methodName = strace[0].getMethodName();
    int lineNum = strace[1].getLineNumber();

    String className = strace[1].getClassName().replaceAll(".{5}$", "");
    String classPath = Class.forName(className).getProtectionDomain().getCodeSource().getLocation().getPath() + className + ".class";

    StringWriter javapOut = new StringWriter();
    com.sun.tools.javap.Main.run(new String[] {"-l", "-c", classPath}, new PrintWriter(javapOut));
    List<String> javapLines = Arrays.asList(javapOut.toString().split("\\r?\\n"));
    int byteCodeStart = -1;
    Map<Integer, Integer> byteCodePointerToJavaPLine = new HashMap<Integer, Integer>();
    Pattern byteCodeIndexPattern = Pattern.compile("^\\s*(\\d+): ");
    for (int n = 0;n < javapLines.size();n++) {
        String javapLine = javapLines.get(n);
        if (byteCodeStart > -1 && (javapLine == null || "".equals(javapLine))) {
            break;
        }
        Matcher byteCodeIndexMatcher = byteCodeIndexPattern.matcher(javapLine);
        if (byteCodeIndexMatcher.find()) {
            byteCodePointerToJavaPLine.put(Integer.parseInt(byteCodeIndexMatcher.group(1)), n);
        } else if (javapLine.contains("line " + lineNum + ":")) {
            byteCodeStart = Integer.parseInt(javapLine.substring(javapLine.indexOf(": ") + 2));
        }
    }

    int varLoadIndex = -1;
    int varTableIndex = -1;
    for (int i = byteCodePointerToJavaPLine.get(byteCodeStart) + 1;i < javapLines.size();i++) {
        if (varLoadIndex < 0 && javapLines.get(i).contains("Method " + methodName + ":")) {
            varLoadIndex = i;
            continue;
        }

        if (varLoadIndex > -1 && javapLines.get(i).contains("LocalVariableTable:")) {
            varTableIndex = i;
            break;
        }
    }

    String loadLine = javapLines.get(varLoadIndex - 1).trim();
    int varNumber;
    try {
        varNumber = Integer.parseInt(loadLine.substring(loadLine.indexOf("aload") + 6).trim());
    } catch (NumberFormatException e) {
        return null;
    }
    int j = varTableIndex + 2;
    while(!"".equals(javapLines.get(j))) {
        Matcher varName = Pattern.compile("\\s*" + varNumber + "\\s*([a-zA-Z_][a-zA-Z0-9_]*)").matcher(javapLines.get(j));  
        if (varName.find()) {
            return varName.group(1);
        }
        j++;
    }
    return null;
}

यह वर्तमान में कुछ गोचरों के साथ काम करता है:

  1. यदि आप इसे संकलित करने के लिए IDE का उपयोग करते हैं, तो यह तब तक काम नहीं कर सकता जब तक कि इसे व्यवस्थापक के रूप में नहीं चलाया जाता है (यह निर्भर करता है कि अस्थायी कक्षा फ़ाइलें कहाँ सहेजी गई हैं)
  2. आपको ध्वज के javacसाथ संकलन करना होगा -g। यह संकलित वर्ग फ़ाइल में स्थानीय चर नामों सहित सभी डीबगिंग जानकारी उत्पन्न करता है।
  3. यह एक आंतरिक जावा एपीआई का उपयोग करता है com.sun.tools.javapजो एक क्लासफाइल के बाईटेकोड को पार्स करता है और एक मानव पठनीय परिणाम पैदा करता है। यह एपीआई केवल JDK पुस्तकालयों में उपलब्ध है, इसलिए आपको या तो JDK जावा रनटाइम का उपयोग करना होगा या अपने classpath में tools.jar को जोड़ना होगा।

यदि प्रोग्राम को कई बार विधि कहा जाता है तो भी यह काम करना चाहिए। दुर्भाग्य से यह तब तक काम नहीं करता है जब आपके पास एक ही लाइन पर कई इनवोकेशन हों। (जो करता है, उसके लिए नीचे देखें)

इसे ऑनलाइन आज़माएं!


व्याख्या

StackTraceElement[] strace = new Exception().getStackTrace();
String methodName = strace[0].getMethodName();
int lineNum = strace[1].getLineNumber();

String className = strace[1].getClassName().replaceAll(".{5}$", "");
String classPath = Class.forName(className).getProtectionDomain().getCodeSource().getLocation().getPath() + className + ".class";

इस पहले भाग में कुछ सामान्य जानकारी मिलती है कि हम किस वर्ग में हैं और फ़ंक्शन का नाम क्या है। यह एक अपवाद बनाकर और स्टैक ट्रेस की पहली 2 प्रविष्टियों को पार्स करके पूरा किया गया है।

java.lang.Exception
    at E.getParamName(E.java:28)
    at E.main(E.java:17)

पहली प्रविष्टि वह रेखा है जिसे अपवाद के रूप में फेंक दिया जाता है, जिस पर हम मेथडनाम को पकड़ सकते हैं और दूसरी प्रविष्टि वह है जहां फ़ंक्शन को कहा गया था।

StringWriter javapOut = new StringWriter();
com.sun.tools.javap.Main.run(new String[] {"-l", "-c", classPath}, new PrintWriter(javapOut));

इस पंक्ति में हम JDK के साथ आने वाले javap निष्पादन योग्य को निष्पादित कर रहे हैं। यह प्रोग्राम क्लास फ़ाइल (बाइटकोड) को पार्स करता है और मानव-पठनीय परिणाम प्रस्तुत करता है। हम इसका उपयोग अल्पविकसित "पार्सिंग" के लिए करेंगे।

List<String> javapLines = Arrays.asList(javapOut.toString().split("\\r?\\n"));
int byteCodeStart = -1;
Map<Integer, Integer> byteCodePointerToJavaPLine = new HashMap<Integer, Integer>();
Pattern byteCodeIndexPattern = Pattern.compile("^\\s*(\\d+): ");
for (int n = 0;n < javapLines.size();n++) {
    String javapLine = javapLines.get(n);
    if (byteCodeStart > -1 && (javapLine == null || "".equals(javapLine))) {
        break;
    }
    Matcher byteCodeIndexMatcher = byteCodeIndexPattern.matcher(javapLine);
    if (byteCodeIndexMatcher.find()) {
        byteCodePointerToJavaPLine.put(Integer.parseInt(byteCodeIndexMatcher.group(1)), n);
    } else if (javapLine.contains("line " + lineNum + ":")) {
        byteCodeStart = Integer.parseInt(javapLine.substring(javapLine.indexOf(": ") + 2));
    }
}

हम यहां कुछ अलग कर रहे हैं। सबसे पहले, हम एक सूची में लाइन द्वारा javap आउटपुट लाइन पढ़ रहे हैं। दूसरा हम बायटेकोड लाइन इंडेक्स का एक नक्शा बना रहे हैं जो जेवैप लाइन इंडेक्स को दर्शाता है। यह हमें बाद में यह निर्धारित करने में मदद करता है कि हम किस पद्धति के आह्वान का विश्लेषण करना चाहते हैं। अंत में हम स्टैक ट्रेस से ज्ञात लाइन नंबर का उपयोग कर रहे हैं यह निर्धारित करने के लिए कि हम किस बायोटेक लाइन इंडेक्स को देखना चाहते हैं।

int varLoadIndex = -1;
int varTableIndex = -1;
for (int i = byteCodePointerToJavaPLine.get(byteCodeStart) + 1;i < javapLines.size();i++) {
    if (varLoadIndex < 0 && javapLines.get(i).contains("Method " + methodName + ":")) {
        varLoadIndex = i;
        continue;
    }

    if (varLoadIndex > -1 && javapLines.get(i).contains("LocalVariableTable:")) {
        varTableIndex = i;
        break;
    }
}

यहां हम उस स्थान को खोजने के लिए एक बार फिर से जाप लाइनों पर पुनरावृत्ति कर रहे हैं, जहां हमारी विधि को आमंत्रित किया जा रहा है और जहां स्थानीय चर तालिका शुरू होती है। हमें उस पंक्ति की आवश्यकता है जहां विधि को लागू किया जाता है क्योंकि इससे पहले की रेखा में चर को लोड करने के लिए कॉल होता है और लोड करने के लिए किस चर (सूचकांक द्वारा) की पहचान करता है। स्थानीय परिवर्तनीय तालिका हमें वास्तव में उस सूचकांक के आधार पर चर के नाम को देखने में मदद करती है जिसे हमने पकड़ा था।

String loadLine = javapLines.get(varLoadIndex - 1).trim();
int varNumber;
try {
    varNumber = Integer.parseInt(loadLine.substring(loadLine.indexOf("aload") + 6).trim());
} catch (NumberFormatException e) {
    return null;
}

यह हिस्सा वास्तव में चर सूचकांक प्राप्त करने के लिए लोड कॉल को पार्स कर रहा है। यह एक अपवाद फेंक सकता है यदि फ़ंक्शन को वास्तव में एक चर के साथ नहीं बुलाया जाता है ताकि हम यहां अशक्त लौट सकें।

int j = varTableIndex + 2;
while(!"".equals(javapLines.get(j))) {
    Matcher varName = Pattern.compile("\\s*" + varNumber + "\\s*([a-zA-Z_][a-zA-Z0-9_]*)").matcher(javapLines.get(j));  
    if (varName.find()) {
        return varName.group(1);
    }
    j++;
}
return null;

अंत में हम स्थानीय चर तालिका में पंक्ति से चर के नाम को पार्स करते हैं। यदि यह नहीं मिला है, तो अशक्त लौटें, हालांकि मैंने ऐसा करने का कोई कारण नहीं देखा है।

यह सब एक साथ डालें

 public static void main(java.lang.String[]);
    Code:
...
      18: getstatic     #19                 // Field java/lang/System.out:Ljava/io/PrintStream;
      21: aload_1
      22: aload_2
      23: invokevirtual #25                 // Method getParamName:(Ljava/lang/String;)Ljava/lang/String;
...
    LineNumberTable:
...
      line 17: 18
      line 18: 29
      line 19: 40
...
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0      83     0  args   [Ljava/lang/String;
          8      75     1     e   LE;
         11      72     2   str   Ljava/lang/String;
         14      69     3  str2   Ljava/lang/String;
         18      65     4  str4   Ljava/lang/String;
         77       5     5    e1   Ljava/lang/Exception;

यह मूल रूप से वही है जो हम देख रहे हैं। उदाहरण कोड में पहला आह्वान लाइन 17 है। लाइन नम्बर 17 में लाइननंबरटेबल में दिखाया गया है कि उस लाइन की शुरुआत बायटेकोड लाइन इंडेक्स 18 है System.out। यह भार है। फिर हमारे पास aload_2मेथड कॉल से ठीक पहले है ताकि हम लोकल वियरेबलटेबल के स्लॉट 2 में वैरिएबल को देखें जो strइस मामले में है।


मज़े के लिए, यहाँ एक ही लाइन पर एक से अधिक फ़ंक्शन कॉल संभालता है। यह फ़ंक्शन को बेकार नहीं होने का कारण बनता है लेकिन यह इस तरह का बिंदु है। इसे ऑनलाइन आज़माएं!


1
इस उत्तर को प्यार करो। उसी तर्ज पर कुछ सोच रहा था। एक टिप्पणी हालांकि, अगर आप इस कार्यक्रम का एक ही पंक्ति में एकाधिक कॉल में शामिल है, तो यह निर्धारित नहीं कर सकता जो एक विधि बुला रहा है (यकीन नहीं यह आपके वर्तमान दृष्टिकोण के ठीक किया जा सकता है), उदाहरण के लिए, ले जाने का प्रयास System.out.println(e.getParamName(str));System.out.println(e.getParamName(str2));System.out.println(e.getParamName(str4));पर TIO लिंक में एक पंक्ति।
पुनपुन 1000

आप javapइस तरह से स्थान को पुनः प्राप्त कर सकते हैं Paths.get(System.getProperty("java.home"), "bin", "javap"):।
ओलिवियर ग्रेजायर

@ OlivierGrégoire धन्यवाद, लेकिन मैं आंतरिक जावा एपि के माध्यम से जावप को स्विच करने के लिए स्विच किया गया, इसलिए मुझे कोड में डिस्क पर सटीक स्थान प्राप्त करने की आवश्यकता नहीं है (बस क्लासपैथ)
पॉक

@ PunPun1000 हाँ, मुझे यकीन नहीं है कि अगर एक अच्छा काम करने के दौरान इसे ठीक करने का एक अच्छा तरीका है, लेकिन मैं कुछ ऐसा एक साथ रख सकता हूं जो सिर्फ मनोरंजन के लिए फ़ंक्शन के बाहर का उपयोग करता है।
प्रहार

1
@ PunPun1000 ने एक संस्करण जोड़ा जो एक लाइन पर कई कॉल को संभाल सकता है। यह केवल फ़ंक्शन से अधिक है इसलिए मैंने उत्तर को अपडेट करने के बजाय केवल एक और TryItOnline लिंक जोड़ा।
प्रहार

14

अजगर २

यह मेरे द्वारा लिखे गए सबसे गंदे कोड के बारे में है लेकिन यह काम करता है। ¯ \ _ (ツ) _ / ¯ एक गैर-मौजूद चर पर एक त्रुटि फेंकता है क्योंकि पायथन आपको एक के साथ फ़ंक्शन को कॉल करने के लिए तुरंत नापसंद करेगा। गैर-चर पर एक त्रुटि भी फेंकता है, लेकिन इसे एक कोशिश के साथ तय किया जा सकता है / यदि आवश्यक हो तो छोड़कर।

import inspect
import re

def name_of(var):
    for i in inspect.getframeinfo(inspect.currentframe().f_back)[3]:
        return re.search(r'\bname_of\s*\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*\)', i).groups()[0]

इसे ऑनलाइन आज़माएं!

यदि हम तर्क को एक स्ट्रिंग के रूप में लेने की अनुमति देते हैं, तो यह अमान्य इनपुट पर मिथ्या मान के उत्पादन की आवश्यकताओं को संतुष्ट करता है।

import inspect
import re

def name_of(var):
    # return var :P

    try:
        eval(var)
    except NameError:
        return False

    for i in inspect.getframeinfo(inspect.currentframe().f_back)[3]:
        try:
            return re.search(r'\bname_of\s*\(\s*[\'"]([A-Za-z_][A-Za-z0-9_]*)[\'"]\s*\)', i).groups()[0]
        except AttributeError:
            return False

इसे ऑनलाइन आज़माएं!


आपने लगभग एक ही उत्तर पोस्ट किया, जबकि मैं अपना स्पष्टीकरण टाइप कर रहा था: डी +1 आपके लिए
डेड पोसुम

1
@DeadPossum हमेशा पोस्ट करें और उत्तर दें और बाद में एक एडिट के रूप में एक स्पष्टीकरण जोड़ें। ;)
अर्जुन

8
@ अर्जुन, ओह बढ़िया तो हमें एडिटगल्फ के साथ-साथ कोडगॉल्फ भी खेलना होगा: P
Wossname

12

मेथेमेटिका

f[x_] := ValueQ @ x && ToString @ HoldForm @ x
SetAttributes[f, HoldFirst]

HoldFirstविशेषता से बचाता fसमारोह लागू करने से पहले अपने तर्क का मूल्यांकन से। ValueQ @ xफिर जाँचता है कि क्या दिए गए तर्क एक चर है जिसे मूल्य दिया गया है। अगर नहीं तो हम सिर्फ Falseशॉर्ट-सर्कुलेटिंग की वजह से लौटते हैं । अन्यथा, हम चर नाम प्राप्त करते हैं ToString @ HoldForm @ x


डांग, गाली देते हुए कि कैसे गणितज्ञ संभालता है And... मुझे पसंद है कि कैसे सही तर्क Andभी एक बूलियन अभिव्यक्ति होना नहीं है।
जुंगवान मिन

मुझे पता है कि यह कोड गोल्फ नहीं है, लेकिन सिर्फ क्यों नहीं f[x_] := ValueQ @ x && HoldForm @ x? यदि यह जांचने की आवश्यकता के लिए नहीं था कि इनपुट एक चर है, तो HoldFormअपने आप काम करेगा।
22 नवंबर को

HoldAllके बजाय HoldFirst?
ग्रेग मार्टिन

1
@ngenisis क्योंकि वह लौटता है HoldForm[a]और नहीं "a"। जबकि उन्हें गणितज्ञ नोटबुक में समान प्रदर्शित किया जाता है, फ़ंक्शन स्वतंत्र रूप से मौजूद होता है, इसलिए मैं एक समाधान चाहता था जो एक स्ट्रिंग लौटाता है।
मार्टिन एंडर

1
व्हाट्सएप को हटाने का अनुरोध क्योंकि ... um ... क्योंकि
कैलकुलेटर

7

मेथेमेटिका

f~SetAttributes~HoldAll;
f[_] = False;
f[x_Symbol?ValueQ] := SymbolName@Unevaluated@x;

गणितज्ञ को हर चीज का मूल्यांकन करना पसंद है , इसलिए इसे रोकने के लिए, हमें इसके खिलाफ लड़ना होगा। अपनी भाषा में।

कैसे?

f~SetAttributes~HoldAll;

मैथेमेटिका को बताता है कि जब भी फ़ंक्शन fको बुलाया जाता है, तो उसके तर्कों का मूल्यांकन नहीं किया जाना चाहिए (अर्थात आयोजित)।


f[_] = False;

जब fएक तर्क, आउटपुट के साथ कहा जाता है False। (?!)


f[x_Symbol?ValueQ] := SymbolName@Unevaluated@x;

जब fएक परिभाषित प्रतीक के साथ कहा जाता है (जिसका मूल्य है), इनपुट के प्रतीक नाम का उत्पादन करें।

पिछली पंक्ति पूर्वता को नहीं लेती है, पहले परिभाषित होने के बावजूद, क्योंकि यह परिभाषा अधिक विशिष्ट है। जैसा कि वोल्फ्राम डॉक्यूमेंटेशन कहता है: गणितज्ञ "अधिक सामान्य परिभाषाओं से पहले विशिष्ट परिभाषाओं को रखने की कोशिश करता है।"

गणितज्ञ बहुत जिद्दी है और जब भी संभव हो चर का मूल्यांकन करने की कोशिश करता रहता है। अतिरिक्त Unevaluatedदेखभाल करता है।


7

सी#

string n<T>(Expression<Func<T>>m) =>
    (m.Body as MemberExpression)?.Member?.Name ?? null;

पूर्ण / प्रारूपित संस्करण:

using System;
using System.Linq.Expressions;

class P
{
    static void Main()
    {
        var apple = "Hello";
        var nil = "Nothing";
        var SOMETHING = 69;

        Console.WriteLine(n(() => apple));
        Console.WriteLine(n(() => nil));
        Console.WriteLine(n(() => SOMETHING));
        Console.WriteLine(n(() => 3.14159));

        Console.ReadLine();
    }

    static string n<T>(Expression<Func<T>>m)
        => (m.Body as MemberExpression)?.Member?.Name ?? null;
}

ऐसा करने का एक और तरीका इस प्रकार है:

public static string GetParameterName<T>(T item)
{
    var properties = typeof(T).GetProperties();

    return properties.Length > 0 ? properties[0].Name : null;
}

हालाँकि, आपको इसे कॉल करना होगा:

GetParameterName(new { apple });

यह फिर 3.14159से लौटने के लिए भी विफल रहता है Lengthऔर इसके लिए आपको इसे निम्नलिखित की तरह कॉल करना होगा:

GetParameterName(new double[]{ 3.14159 });

C # 6.0 में भी हमारे पास है:

nameof

लेकिन यह संकलित नहीं करेगा यदि आप इसे कुछ ऐसे पास करते हैं जो चर नहीं है 3.14159। मेरा मानना ​​है कि यह संकलन समय पर इनपुट का भी मूल्यांकन करता है इसलिए ऐसा लगता है कि यह उस आवश्यकता को भी विफल करता है।


यह थोड़ा विचित्र है ... क्योंकि लैम्ब्डा सामान बिल्कुल आवश्यक है (यानी आप सिर्फ चर में पारित नहीं कर सकते हैं, आपको कुछ पारित करना होगा जो कि संकलन को पहचानना चाहिए Expression)। आपकी भी गिनती होनी चाहिए using System.Linq.Expressions;
VisualMelon

क्या यह "अमूर्त सिंटैक्स ट्री फॉर्म में तर्क प्राप्त करना" के रूप में गिना जाता है?
मैटी विर्ककुनेन

@VisualMelon मुझे C # में ऐसा करने का कोई अन्य तरीका नहीं मिला, इसलिए मैंने इसे इस तरह से किया। इसके अलावा यह कोड-गोल्फ नहीं है, इसलिए यह वास्तव में मायने नहीं रखता है,
TheLethalCoder

... क्षमा करें, एहसास नहीं था कि एक बाइट गिनती नहीं थी!
विजुअलमेल

6

Matlab

varname = @(x) inputname(1);

एक फंक्शन के भीतर कुछ प्रीसेट वैरिएबल होते हैं जैसे varargin या nargin, हमारे पास भी inputname

यहाँ से चोरी हो गई


मुझे कभी नहीं पता था कि यह अस्तित्व में है। मैं इस एक सा के साथ चारों ओर खेला है, और शायद आप इस मणि पसंद करेंगे:x=42;y=54; f=@(x)eval(inputname(1));f(x),f(y)
Sanchises

हाहा, eval==evil= डी (यह वास्तव में साथ काम करता है x=42;y=54; f=@(x)eval('inputname(1)');f(x),f(y))
दोष

हाँ, यह सिर्फ इतना है कि एक अनाम फ़ंक्शन किसी भी कार्यक्षेत्र चर के बारे में नहीं जानता है, इसलिए eval केवल मूल्यांकन कर सकता है x, और फिर evalफ़ंक्शन तर्क को बदल रहा है, न कि कार्यक्षेत्र चर।
सानचिस

6

आर

function(x) if (identical(substitute(x), x)) FALSE else substitute(x)

substituteएक निर्विवाद अभिव्यक्ति के लिए पार्स ट्री लौटाता है। identicalसशर्त सुनिश्चित करती है कि इस unevaluated अभिव्यक्ति अभिव्यक्ति ही के समान नहीं है, यानी कि पैरामीटर में पारित एक शाब्दिक नहीं है।


4

अजगर २

कुछ शोध किए गए हैं। और यह अजगर में संभव प्रतीत होता है, लेकिन मुझे अभी भी कुछ परेशानियों की उम्मीद है।
समाधान सही नहीं है, क्योंकि यह कोड की कुछ संरचना को मानता है। फिर भी मैंने इसे अभी भी नहीं तोड़ा।

import inspect
import re

def get_name(var):
    called = inspect.getouterframes(inspect.currentframe())[1][4][0]
    return re.search('(?<=get_name\().*(?=\))', called).group().lstrip().rstrip()

यह चारों ओर के दायरे को देखने और खोजने के लिए निरीक्षण करता है जहां फ़ंक्शन get_nameकहा जाता है। उदाहरण के लिए inspect...[1]वापस आ जाएगा

(< frame object at 0x01E29030>, 'C:/Users/---/PycharmProjects/CodeGolf/Name_var.py', 14, '< module>', ['print get_name( a )\n'], 0)

और inspect...[1][4]हमें कोड के साथ सूची दिखाएगा, जहां फ़ंक्शन कहा जाता है:

['print get_name( a )\n']

उसके बाद मैंने तर्क का नाम पुनः प्राप्त करने के लिए रेगेक्स का उपयोग किया

re.search('(?<=get_name\().*(?=\))', called).group()

और .lstrip().rstrip()सभी व्हाट्सएप को हटाने के लिए जिसे ब्रैकेट में रखा जा सकता है।

कुछ मुश्किल इनपुट के साथ उदाहरण


4

शक्ति कोशिका

function t($t){(variable($MyInvocation.Line.Split(' $'))[-1]-ea si).Name}

$apple = 'hi'
t $apple
apple

t 3.141

लेकिन यह मज़बूती से काम नहीं करता है, यह अल्पविकसित है।


यह कोड गोल्फ नहीं है।
ओकेक्स

@ ओएक्स ओह, उफ़, तो यह नहीं है।
TessellatingHeckler

4

पीएचपी

वैश्विक चर की सरणी में चर मूल्य अद्वितीय है

function v($i){echo"$".array_search($i,$GLOBALS);}

इसे ऑनलाइन आज़माएं!

PHP , 96 बाइट्स

function v($i){
echo($i==end($g=$GLOBALS))?"$".key(array_slice($g,-1)):0;
}
$hello=4;
v($hello);

इसे ऑनलाइन आज़माएं!

जरूरत है कि वेरिएबल को फंक्शन कॉल में सीधे इनिशियलाइज़ किया जाए।

जाँचता है कि पिछले वैश्विक चर बराबर समर्पण चर है


यह कोड गोल्फ नहीं है।
ओकेक्स

@ ओक्स मुझे पता है कि इस समय मेरे पास कोई बेहतर विचार नहीं है।
जोर्ग हल्सरमैन


4

जावास्क्रिप्ट (ES6)

window( Object.getOwnPropertyNames(w)) में सभी संपत्ति नामों के लिए, उस संपत्ति के लिए एक गेटर को परिभाषित करने का प्रयास करें जो संपत्ति का नाम लौटाता है।

फिर, एक मानचित्र में एक प्रविष्टि जोड़ें Mजहां कुंजी संपत्ति का संभवतः (ओवरराइड किया गया) मूल्य है, और मूल्य संपत्ति का नाम है।

फ़ंक्शन fकेवल एक चर (यानी की एक संपत्ति window) लेता है और Mउस मूल्य के लिए प्रविष्टि लौटाता है ।

let
    w = window,
    M = new Map(),
    L = console.log,
    P = Object.getOwnPropertyNames(w),
    D = Object.defineProperty

for(const p of P){
    try {
        D(w, p, {
            get(){
                return p
            }
        })
    } catch(e){ L(e) }

    try {
        M.set(w[p], p)
    } catch(e){ L(e) }
}

let f = v => M.get(v)

यह windowस्वयं के अलावा सभी अंतर्निहित वैश्विक चरों के लिए काम करता है, क्योंकि इसे अलग करने का कोई तरीका नहीं है top(जब तक कि एक फ्रेम में नहीं चलाया जाता है):

L( P.filter(p => p !== f(w[p])) )
// -> ['window']

किसी कारण के लिए, मैं एक त्रुटि हो रही है: L not a function। क्यों होता है कि होता है?
कालेब क्लेवटर

वाह! मैं कुछ ही समय में ईएस 6 से अधिक गहरा हो गया हूं।
एमडी एक्सएफ

@CalebKleveter D'oh! मैं दूसरी पंक्ति में अल्पविराम भूल गया। यह समस्या है या नहीं हो सकता है।
darrylyeo

3

पर्ल 5 + देवल :: कॉलर

use 5.010;
use Devel::Caller qw/caller_vars/;
use Scalar::Util qw/refaddr/;

sub v {
   # find all operands used in the call, formatted as variable names
   my @varsused = caller_vars(0,1);
   scalar @varsused == 1 or return; # exactly one operand, or return false
   $varsused[0] =~ s/^\$// or return; # the operand actually is a variable
   # it's possible we were given an expression like "~$test" which has only
   # one operand, but is not a variable in its own right; compare memory
   # addresses to work this out
   refaddr \ ($_[0]) == refaddr \ (${$varsused[0]}) or return;
   return '$' . $varsused[0];
}

# some test code

our $test = 1;
our $test2 = 2;
our $test3 = 3;

say v($test2);
say v(2);
say v(~$test3);
say v($test);
say v($test + 1);
say v(++$test);
say v($test3);

हम कॉल स्टैक को चलाने के लिए, फ़ंक्शन को कॉल की तलाश करने के लिए Devel :: Caller (एक डिबगर-जैसे मॉड्यूल) का उपयोग करते हैं, और तर्क के भीतर सभी ऑपरेंड को वापस करते हुए, उन्हें चर नामों के रूप में लौटाते हैं। यदि एक ऑपरेंड से अधिक (या कम) है, तो हमें एक चर के साथ नहीं बुलाया गया था। यदि ऑपरेंड वैरिएबल नहीं था, तो उसका कोई नाम नहीं होगा और हम इसका भी पता लगा सकते हैं।

सबसे मुश्किल मामला यह है कि अगर हम एक चर को शामिल करते हुए एक-ऑपरेंड अभिव्यक्ति प्राप्त करते हैं, जैसे कि ~$x। हम यह पता लगा सकते हैं कि क्या यह प्रतीक तालिका ( ${…}प्रतीकात्मक संदर्भ वाक्यविन्यास का उपयोग करके ) से चर का संदर्भ लेते हुए हुआ है और इसके स्मृति पते की तुलना हम एक तर्क के रूप में पारित कर चुके हैं (जो कि, सुविधाजनक रूप से, संदर्भ द्वारा पारित किया गया है) )। यदि वे अलग हैं, तो हमारे पास एक अकेला चर के बजाय एक अभिव्यक्ति है।

ध्यान दें कि यदि हम इस फ़ंक्शन को किसी एकल चर पर पूर्वनिर्धारण या पूर्वनिर्धारण अभिव्यक्ति के साथ कहते हैं v(--$x), तो हम $xवापस आ जाते हैं। ऐसा इसलिए है क्योंकि यह वास्तव में चर है जो इस मामले में फ़ंक्शन को पारित किया जा रहा है; यह पहले से ही बढ़ा या घटा हुआ है। मुझे आशा है कि यह उत्तर को अयोग्य घोषित नहीं करेगा। (एक तरह से, यह इसे बेहतर बनाता है, क्योंकि यह दिखाता है कि हम केवल स्रोत कोड पढ़ने के बजाय तर्क की जाँच कर रहे हैं।)


3

पीएचपी

जबकि अन्य PHP सबमिशन केवल तभी परीक्षण करते हैं यदि दिए गए मान किसी वैश्विक मान से मेल खाते हैं, यह संस्करण मान का संदर्भ लेकर काम करता है:

// take a reference to the global variable
function f(&$i){
  foreach(array_reverse($GLOBALS) as $key => $value)
    if($key != 'GLOBALS') {
      // Set the value of each global to its name
      $GLOBALS[$key] = $key;
    }

  foreach($GLOBALS as $key => $value)
    if($key != 'GLOBALS' && $key != $value) {
      // The values mismatch so it had a reference to another value
      // we delete it
      unset($GLOBALS[$key]);
      // and update the value to its name again
      $GLOBALS[$key] = $key;
    }

  echo '$', is_array($i) ? 'GLOBALS' : $i, "\n";
}

यह अब भी काम करना चाहिए भले ही वैश्विक चर कॉलिंग के समय किसी अन्य मूल्य का संदर्भ हो।

इसका परीक्षण यहां करें


सीखने के प्रयास के लिए महान और धन्यवाद
Jörg Hülsermann

@ JörgHülsermann यहां तक ​​कि इसे सुधारने का एक तरीका मिल गया!
क्रिस्टोफ

3

Röda

f(&a...) {
	a() | name(_) | for str do
		false if [ "<" in str ] else [str]
	done
}

इसे ऑनलाइन आज़माएं!

रोड़ा के पास इसके लिए एक बेसिन फ़ंक्शन है - name। दुर्भाग्य से, हालांकि, यह एक चर मान नहीं देता है जब एक चर नहीं दिया जाता है।

यह कोड संदर्भ शब्दार्थ की कई विशेषताओं का दुरुपयोग करता है। स्पष्टीकरण लाइन द्वारा लाइन:

f(&a...) {

फ़ंक्शन संदर्भ तर्कों की एक चर संख्या लेता है ( &a...)। संदर्भों की सूची बनाने के लिए रोडा में यह एकमात्र तरीका है।

a() | name(_) | for str do

दूसरी पंक्ति में तत्वों aको धारा ( a()) में धकेल दिया जाता है । ये तत्व संदर्भ हैं यदि फ़ंक्शन को चर और सामान्य मान दिए गए थे अन्यथा।

तत्वों को अंडरस्कोर लूप का उपयोग करके पुनरावृत्त किया जाता है। अंडरस्कोर सिंटेक्स forछोरों के लिए सिंटैक्स चीनी है, इसलिए name(_)इसके बराबर है name(var) for varforलूप में उपयोग किए जाने वाले वेरिएबल का नाम फॉर्म का है <sfvN>जहां एन भिन्न होता है। (यानी। " name(<sfv1>) for <sfv1>") उपयोगकर्ता द्वारा परिभाषित चर को समाहित करना <या रखना गैरकानूनी है >, इसलिए उत्पन्न नाम मौजूदा चर नामों से नहीं टकराते।

name()समारोह को देखते हुए वैरिएबल का नाम देता है। यदि aपुनरावृत्त होने वाला तत्व एक संदर्भ है, तो यह वह चर है जिसे दिया गया है name। अन्यथा, यदि तत्व एक सामान्य मूल्य था, तो दिया गया nameचर अंडरस्कोर वैरिएबल है <sfvN>। यह रोड़ा में संदर्भों के शब्दार्थ के कारण है: यदि कोई फ़ंक्शन संदर्भ को स्वीकार करता है और फ़ंक्शन को संदर्भ चर दिया जाता है, तो पारित मूल्य संदर्भ चर को इंगित नहीं करता है, लेकिन संदर्भ चर को इंगित करता है।

false if [ "<" in str ] else [str]

तीसरी पंक्ति में हम जांचते हैं कि स्ट्रीम में चर नाम में कोई <वर्ण है या नहीं। यदि ऐसा है, तो यह एक अंडरस्कोर वैरिएबल है और पास किया fगया मान संदर्भ नहीं था। अन्यथा हम संदर्भ का नाम आउटपुट करते हैं।

यह समाधान कार्य नहीं करता है यदि फ़ंक्शन को दिया गया चर संदर्भ या अंडरस्कोर वैरिएबल है। हालाँकि, यह प्रश्न निर्दिष्ट करता है कि केवल वैश्विक चर को ही संभाला जाना चाहिए, और वे Röda में संदर्भ या अंडरस्कोर चर नहीं हो सकते हैं।


1

रूबी , 46 बाइट्स

लगता है कि मैंने कभी भी रूबी के लिए लिखे गए सबसे गंदे कोड को देखा।

इसके लिए आवश्यक है कि आपके द्वारा कहे जाने वाले वैश्विक वैरिएबल्स का एक अनूठा मूल्य हो जो किसी भी अन्य वैरिएबल वैरिएबल पर न हो, क्योंकि रूबी में इस चुनौती को करने का एकमात्र तरीका सभी वैश्विक चरों पर एक खोज करना और पहला मैच वापस करना है। ओपी कहता है कि यह ठीक है, और यदि मेरा समाधान वैध है तो न्याय करने के लिए स्वतंत्र है।

ध्यान दें कि $यदि आप अतिरिक्त परीक्षण केस सामान जोड़ना चाहते हैं, तो रूबी में वैश्विक चर शुरू होते हैं।

->v{global_variables.find{|n|eval(n.to_s)==v}}

इसे ऑनलाइन आज़माएं!


1

पीएचपी

function f($v){foreach($GLOBALS as$n=>$x)$x!=$v?:die($n);}

यदि मान मिलता है, तो चर नाम प्रिंट करें और बाहर निकलें। कुछ नहीं प्रिंट करें और बाहर न निकलें।

चर नाम वापस करने के लिए 61 बाइट्स या NULL:

function f($v){foreach($GLOBALS as$n=>$x)if($x==$v)return$n;}

इसे नामित फ़ंक्शंस नहीं मिलेंगे, केवल वे जो चर को सौंपे गए हैं।
और एक PHP फ़ंक्शन का पता नहीं लगा सकता है कि एक पैरामीटर को संदर्भ या मूल्य द्वारा प्रदान किया गया है। फ़ंक्शन केवल पहला नाम लौटाएगा जहां मान फ़ंक्शन पैरामीटर मान से मेल खाता है।

इसे ऑनलाइन टेस्ट करें


1

शक्ति कोशिका

नया संस्करण लेकिन PowerShell 3.0 से शुरू होता है

function p{[scriptblock]::create($myinvocation.line).ast.findall({$args[0]-is[Management.Automation.Language.VariableExpressionAst]},0)[0]|% v*h|% u*|%{($_,!1)[!$_]}}

यह ऑनलाइन की कोशिश करो!

पुराना वर्जन

function p{$t=[management.automation.psparser]::tokenize($myinvocation.line,[ref]@())|? type -match '^[cv]'|? start|% content;($t,!1)[!$t]}

यह ऑनलाइन की कोशिश करो!



0

जावास्क्रिप्ट (ES6)

यह आवश्यक है कि फ़ंक्शन को दिया गया वेरिएबल का मान उस वेरिएबल के लिए अद्वितीय हो। undefinedएक चर पारित नहीं किया गया था, तो रिटर्न ।

arg=>{
    for(key in this)
        if(this[key]===arg)
            return key
}

कोशिश करो

किसी कारण से, यह एक स्निपेट में एक क्रॉस-ऑरिजनल त्रुटि फेंकता है जब "शाब्दिक" पास होता है।

var fn=
    arg=>{
        for(key in this)
            if(this[key]===arg)
                return key
    },
str="string",
int=8,
arr=[1,2,3],
obj={a:1}
console.log(fn(fn))
console.log(fn(str))
console.log(fn(int))
console.log(fn(arr))
console.log(fn(obj))


व्याख्या

वैश्विक ऑब्जेक्ट ( this) में सभी प्रविष्टियों के माध्यम से लूप करें , यह जांचने पर कि फ़ंक्शन में दिए गए तर्क के मूल्य के बराबर हर एक का मूल्य क्या है। यदि एक मिलान प्रविष्टि पाई जाती है, तो इसकी कुंजी (नाम) फ़ंक्शन से बाहर निकलती है।


विकल्प

उपरोक्त आवश्यकताओं के साथ ही

arg=>
    [...Object.keys(this)].filter(key=>
        this[key]==arg
    ).pop()

2
मुझे लगता है कि यह विफल रहता है अगर दो ग्लोबल्स का एक ही मूल्य है।
मार्टिन एंडर


@MartinEnder; हाँ, यह मानता है कि पारित चर को दिया गया मान उस चर के लिए अद्वितीय है; जब मैंने पोस्ट किया तो इसे शामिल करना भूल गया।
झबरा

@CalebKleveter; उनमें से कुछ इस तथ्य के कारण हैं कि आपके द्वारा पास किए जा रहे चर का मान उस चर के लिए अद्वितीय नहीं है और इसके कुछ कारण अमान्य चर नामों (जैसे, hello--) के कारण हैं। इसके अलावा, आपको इसके varबजाय उपयोग करने की आवश्यकता होगी let
शैगी

1
@ CalebKleveter, के बीच में और अधिक अंतर के बारे में अधिक जानकारी के लिए यहाँ देखें । आपके दूसरे प्रश्न के लिए: ऐसा इसलिए हुआ क्योंकि आपके पास आपके वैश्विक दायरे में नामित एक चर है और इसका एक मूल्य है । उपरोक्त परीक्षण से पहले इसे चलाकर आप अपने वैश्विक दायरे में मौजूद वैरिएबल और उनके मूल्यों की जांच कर सकते हैं:letvarIN_GLOBAL_SCOPE1for(x in this)console.log(x+": "+this[x])
झबरा

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.