blob: 307941db8b1c0117357f5e7ebd3de7392d20d41a [file] [log] [blame]
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.python;
import com.google.common.collect.ImmutableList;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.util.ObjectUtils;
import com.intellij.util.PathUtil;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.PyStringLiteralExpression;
import com.intellij.psi.util.QualifiedName;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static com.intellij.openapi.util.text.StringUtil.endsWith;
import static com.intellij.openapi.util.text.StringUtil.startsWith;
/**
* @author Alexei Orischenko
* @author vlan
*/
public class PythonStringUtil {
private static final ImmutableList<String> QUOTES = ImmutableList.of("'''", "\"\"\"", "'", "\"");
private PythonStringUtil() {
}
/**
* 'text' => text
* "text" => text
* text => text
* "text => "text
*
* @return string without heading and trailing pair of ' or "
*/
@NotNull
public static String getStringValue(@NotNull String s) {
return getStringValueTextRange(s).substring(s);
}
public static TextRange getStringValueTextRange(@NotNull String s) {
final Pair<String, String> quotes = getQuotes(s);
if (quotes != null) {
return TextRange.create(quotes.getFirst().length(), s.length() - quotes.getSecond().length());
}
return TextRange.allOf(s);
}
@NotNull
public static String removeFirstPrefix(@Nullable String s, String separator) {
if (s != null) {
int pos = s.indexOf(separator);
if (pos != -1) {
return s.substring(pos + separator.length());
}
}
return "";
}
@NotNull
public static String removeLastSuffix(@Nullable String s, String separator) {
if (s != null) {
int pos = s.lastIndexOf(separator);
if (pos != -1) {
return s.substring(0, pos);
}
}
return "";
}
public static boolean isPath(@Nullable String s) {
if (!StringUtil.isEmpty(s)) {
s = ObjectUtils.assertNotNull(s);
s = FileUtil.toSystemIndependentName(s);
final List<String> components = StringUtil.split(s, "/");
for (String name : components) {
if (name == components.get(0) && SystemInfo.isWindows && name.endsWith(":")) {
continue;
}
if (!PathUtil.isValidFileName(name)) {
return false;
}
}
return true;
}
return false;
}
public static boolean isEmail(String s) {
if (!StringUtil.isEmpty(s)) {
Pattern p = Pattern.compile("^[\\w\\.-]+@([\\w\\-]+\\.)+[a-z]{2,4}$");
Matcher m = p.matcher(s);
return m.matches();
}
return false;
}
@NotNull
public static String getFirstPrefix(String s, String separator) {
if (s != null) {
int pos = s.indexOf(separator);
if (pos != -1) {
return s.substring(0, pos);
}
}
return s != null ? s : "";
}
public static String getLastSuffix(String s, String separator) {
if (s != null) {
int pos = s.lastIndexOf(separator);
if (pos != -1) {
return s.substring(pos + 1);
}
}
return "";
}
/**
* Replaces word after last dot from string s to newElementName.
* For example 'yy.xxx.foo' can be renamed to 'yy.xxx.bar'
*
* @param s
* @param newElementName
* @return
*/
public static String replaceLastSuffix(String s, String separator, String newElementName) {
Pair<String, String> quotes = null;
if (isQuoted(s)) {
quotes = getQuotes(s);
s = stripQuotesAroundValue(s);
}
s = removeLastSuffix(s, separator);
if (s.length() > 0) {
s += separator;
}
s += newElementName;
if (quotes != null) {
s = quotes.first + s + quotes.second;
}
return s;
}
public static TextRange lastSuffixTextRange(@NotNull String text, String separator) {
int offset = text.lastIndexOf(separator) + 1;
int length = text.length() - offset;
return TextRange.from(offset + 1, length);
}
/**
* Handles unicode and raw strings
*
* @param text
* @return false if no quotes found, true otherwise
* sdfs -> false
* ur'x' -> true
* "string" -> true
*/
public static boolean isQuoted(@Nullable String text) {
return text != null && getQuotes(text) != null;
}
/**
* Handles unicode and raw strings
*
* @param text
* @return open and close quote (including raw/unicode prefixes), null if no quotes present in string
* 'string' -> (', ')
* UR"unicode raw string" -> (UR", ")
*/
@Nullable
public static Pair<String, String> getQuotes(@NotNull final String text) {
boolean start = true;
int pos = 0;
for (int i = 0; i < text.length(); i++) {
final char c = Character.toLowerCase(text.charAt(i));
if (start) {
if (c == 'u' || c == 'r' || c == 'b') {
pos = i + 1;
}
else {
start = false;
}
}
else {
break;
}
}
final String prefix = text.substring(0, pos);
final String mainText = text.substring(pos);
for (String quote : QUOTES) {
final Pair<String, String> quotes = getQuotes(mainText, prefix, quote);
if (quotes != null) {
return quotes;
}
}
return null;
}
@Nullable
private static Pair<String, String> getQuotes(@NotNull String text, @NotNull String prefix, @NotNull String quote) {
final int length = text.length();
final int n = quote.length();
if (length >= 2 * n && text.startsWith(quote) && text.endsWith(quote)) {
return Pair.create(prefix + text.substring(0, n), text.substring(length - n));
}
return null;
}
@Nullable
public static String intersect(String fullName, String elementStringValue) {
QualifiedName fullQName = QualifiedName.fromDottedString(fullName);
QualifiedName stringQName = QualifiedName.fromDottedString(elementStringValue);
String[] s1 = stringQName.getComponents().toArray(new String[stringQName.getComponentCount()]);
String[] s2 = fullQName.getComponents().toArray(new String[fullQName.getComponentCount()]);
for (int i = s1.length - 1; i >= 0; i--) {
boolean flag = true;
if (i > s2.length - 1) {
continue;
}
for (int j = 0; j <= i; j++) {
if (!s1[i - j].equals(s2[s2.length - j - 1])) {
flag = false;
break;
}
}
if (flag) {
StringBuilder res = new StringBuilder("");
for (int j = 0; j <= i; j++) {
if (j > 0) {
res.append(".");
}
res.append(s1[j]);
}
return res.toString();
}
}
return null;
}
public static TextRange getTextRange(PsiElement element) {
if (element instanceof PyStringLiteralExpression) {
final List<TextRange> ranges = ((PyStringLiteralExpression)element).getStringValueTextRanges();
return ranges.get(0);
}
else {
return new TextRange(0, element.getTextLength());
}
}
@Nullable
public static String getText(@Nullable PyExpression ex) {
if (ex == null) {
return null;
}
else {
return ex.getText();
}
}
@Nullable
public static String getStringValue(@Nullable PsiElement o) {
if (o == null) {
return null;
}
if (o instanceof PyStringLiteralExpression) {
PyStringLiteralExpression literalExpression = (PyStringLiteralExpression)o;
return literalExpression.getStringValue();
}
else {
return o.getText();
}
}
public static String stripQuotesAroundValue(String text) {
Pair<String, String> quotes = getQuotes(text);
if (quotes == null) {
return text;
}
return text.substring(quotes.first.length(), text.length() - quotes.second.length());
}
public static boolean isRawString(String text) {
text = text.toLowerCase();
if (text.startsWith("u")) {
text = text.substring(1);
}
return isStringPrefixedBy(text.toLowerCase(), "r");
}
private static boolean isStringPrefixedBy(String text, String prefix) {
return (startsWith(text, prefix + "\"") && endsWith(text, "\"")) || (startsWith(text, prefix + "\'") && endsWith(text, "\'"));
}
}